How to segment a connected area based on color depth in opencv

I have an image like enter image description here which I need to segment the image into 8 blocks.

I tried this threshold method

img_gray = cv2.imread(input_file,cv2.IMREAD_GRAYSCALE) ret,thresh = cv2.threshold(img_gray,254,255,cv2.THRESH_BINARY) = kernel = np.array(cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3), (-1, -1))) img_open = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel) cv2.imshow('abc',img_open) ret1,thresh1 = cv2.threshold(img_open,254,255,cv2.THRESH_BINARY_INV) # contours, hierarchy = cv2.findContours(thresh1, cv2.RETR_CCOMP ,cv2.CHAIN_APPROX_NONE) for i in range(len(contours)): if len(contours[i]) > 20: x, y, w, h = cv2.boundingRect(contours[i]) cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2) print (x, y),(x+w, y+h) 

after the threshold enter image description here

the end result - some blocks connected together form into a large segment, which I did not expect. enter image description here enter image description here enter image description here Any other ways to get it around

+5
source share
2 answers

I will try to give you a sketch of an algorithm that separates machines based on depth gradients. Alas, just by looking at the contour of large depth gradients, the cars are not perfectly separated, therefore, "refinement" of the boundary contour is required. Once the contours are complete, a simple clustering of components is enough to separate the cars.

Here is my code (in Matlab, but I am pretty sure that it is not too complicated to find equivalent opencv functions):

 img = imread('http://i.stack.imgur.com/8lJw8.png'); % read the image depth = double(img(:,:,1)); depth(depth==255)=-100; % make the background VERY distinct [dy dx] = gradient(depth); % compute depth gradients bmsk = sqrt(dx.^2+dy.^2) > 5; % consider only significant gradient % using morphological operations to "complete" the contours around the cars bmsk = bwmorph( bwmorph(bmsk, 'dilate', ones(7)), 'skel'); % once the contours are complete, use connected components cars = bwlabel(~bmsk,4); % segmentation mask st = regionprops(cars, 'Area', 'BoundingBox'); % display the results figure; imshow(img); hold all; for ii=2:numel(st), % ignore the first segment - it the background if st(ii).Area>200, % ignore small regions as "noise" rectangle('Position',st(ii).BoundingBox, 'LineWidth', 3, 'EdgeColor', 'g'); end; end; 

Output signal

enter image description here

and

enter image description here

Not perfect, but brings you close enough.

Further reading:

  • bwmorph : perform morphological operations.
  • bwlabel : display a segmentation mask (marking) of connected components.
  • regionprops : calculate statistics (e.g., region and bounding box) for image regions.

Thinking about it, there are such nice gradients in the depth, you can threshold the depth gradient and get good connected components.

+4
source

Naive approach (but it works)

Step 1: After reading the image in the gray scale, the threshold value for obtaining lower cars.

 ret1, car_thresh1 = cv2.threshold(cars, 191, 254, 0) 

who gave me this. carsBottom

Step 2: Subtract This Image From The Main Image

 car_thresh2 = car_thresh1 - cars 

who gave me this. enter image description here

Step 3: Threshold of the subtracted image

 ret3, cars_thresh3 = cv2.threshold(car_thresh2, 58, 255, 0) 

who gave me this carsTop

Then I just did what you did to extract and draw outlines in the Bottom machines and machines, and this is the result. cars

+1
source

Source: https://habr.com/ru/post/1270089/


All Articles