Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Extracting Curved Contours

So I have been experimenting with OpenCV and extracting a specific portion from an image with python.

My test image is:

enter image description here

From this image, I want to draw the contours around that stockpile of soil as follows:

(Note: This has been done in Paint)

enter image description here

I have tried following things:

  1. Reading the Image and converting it into Grayscale
  2. Morphological Transformation and thresholding as follows:

But I am not sure what to do next? How to extract the aforementioned part of the image?

import cv2

img = cv2.imread('Feature Extraction/soil_stockpile_test_image.png', 
cv2.IMREAD_GRAYSCALE)
blur = cv2.GaussianBlur(img, (1, 1), 2)
h, w = img.shape[:2]

# Morphological gradient

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
gradient = cv2.morphologyEx(blur, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('Morphological gradient', gradient)

#Contours
thresh = cv2.threshold(img,150, 255,cv2.THRESH_BINARY_INV)[1]
cnts, h = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow('thresh', thresh)

I tried the histogram back projection method. It somewhat worked but it still shows some unwanted part of the image. I just want the stockpile to be shown in the result.

Here is the code and the resulting image:

# Original Image
orig_img = cv2.imread('Feature Extraction/soil_stockpile_test_image.png')
roi = cv2.imread('Feature Extraction/roi_soil.png')

# HSV Image
hsv_img = cv2.cvtColor(orig_img, cv2.COLOR_BGR2HSV)
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)

# Region of Interest
roi_hist = cv2.calcHist([hsv_roi], [0, 1], None, [180, 256], [0, 180, 0, 256])
mask = cv2.calcBackProject([hsv_img], [0, 1], roi_hist, [0, 180, 0, 256], 1)


# Remove Noise
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
mask = cv2.filter2D(mask, -1, kernel)
_, mask = cv2.threshold(mask, 210, 255, cv2.THRESH_BINARY)

# Merge and perform bitwise operation
mask = cv2.merge((mask, mask, mask))
result = cv2.bitwise_and(orig_img, mask)

#cv2.imshow('HSV Image', hsv_img)
#cv2.imshow('Region of Interest', roi)
#cv2.imshow('Mask', mask)
cv2.imshow('Result', result)

Result:

enter image description here

Extracting Curved Contours

So I have been experimenting with OpenCV and extracting a specific portion from an image with python.

My test image is:

enter image description here

From this image, I want to draw the contours around that stockpile of soil as follows:

(Note: This has been done in Paint)

enter image description here

I have tried following things:

  1. Reading the Image and converting it into Grayscale
  2. Morphological Transformation and thresholding as follows:

But I am not sure what to do next? How to extract the aforementioned part of the image?

import cv2

img = cv2.imread('Feature Extraction/soil_stockpile_test_image.png', 
cv2.IMREAD_GRAYSCALE)
blur = cv2.GaussianBlur(img, (1, 1), 2)
h, w = img.shape[:2]

# Morphological gradient

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
gradient = cv2.morphologyEx(blur, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('Morphological gradient', gradient)

#Contours
thresh = cv2.threshold(img,150, 255,cv2.THRESH_BINARY_INV)[1]
cnts, h = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow('thresh', thresh)

I tried the histogram back projection method. It somewhat worked but it still shows some unwanted part of the image. I just want the stockpile to be shown in the result.

Here is the code and the resulting image:

# Original Image
orig_img = cv2.imread('Feature Extraction/soil_stockpile_test_image.png')
roi = cv2.imread('Feature Extraction/roi_soil.png')

# HSV Image
hsv_img = cv2.cvtColor(orig_img, cv2.COLOR_BGR2HSV)
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)

# Region of Interest
roi_hist = cv2.calcHist([hsv_roi], [0, 1], None, [180, 256], [0, 180, 0, 256])
mask = cv2.calcBackProject([hsv_img], [0, 1], roi_hist, [0, 180, 0, 256], 1)


# Remove Noise
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
mask = cv2.filter2D(mask, -1, kernel)
_, mask = cv2.threshold(mask, 210, 255, cv2.THRESH_BINARY)

# Merge and perform bitwise operation
mask = cv2.merge((mask, mask, mask))
result = cv2.bitwise_and(orig_img, mask)

#cv2.imshow('HSV Image', hsv_img)
#cv2.imshow('Region of Interest', roi)
#cv2.imshow('Mask', mask)
cv2.imshow('Result', result)

Result:

enter image description here

Edit 1:

After using the grab cut algorithm, with the following code, this is the result I obtained:

# Grab Cut Mask
img = cv2.imread('Feature Extraction/soil_stockpile_test_image.png')

# These params have been hardcoded. Need to be changed for every image.
top_left_x = 300
top_left_y = 150
bottom_right_x = 600
bottom_right_y = 350
Green_color = (0, 255, 0)

# Draw the rectangle
output = cv2.rectangle(img,
                (top_left_x, top_left_y),
                (bottom_right_x, bottom_right_y),
                color=Green_color, thickness=3)

#cv2.imwrite('Output_Image_with_Rectangle.jpg', output)
#cv2.imshow('Output Image with Rectangle', output)

# Grab Cut Mask
mask = np.zeros(img.shape[:2],np.uint8)

bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)

rect = (top_left_x, top_left_y, bottom_right_x, bottom_right_y)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)

mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
new_img = img*mask2[:,:,np.newaxis]

cv2.imwrite('Grab_Cut_img.jpg', new_img)
plt.imshow(new_img),plt.colorbar(),plt.show()

image description

But there is still some black part there. Can I resize this grab cut image? Also, How do i do that? Also, in the image, you can see that there is still some background. How do I suppress this?

I really need your help. Thanks.

Extracting Curved Contours

So I have been experimenting with OpenCV and extracting a specific portion from an image with python.

My test image is:

enter image description here

From this image, I want to draw the contours around that stockpile of soil as follows:

(Note: This has been done in Paint)

enter image description here

I have tried following things:

  1. Reading the Image and converting it into Grayscale
  2. Morphological Transformation and thresholding as follows:

But I am not sure what to do next? How to extract the aforementioned part of the image?

import cv2

img = cv2.imread('Feature Extraction/soil_stockpile_test_image.png', 
cv2.IMREAD_GRAYSCALE)
blur = cv2.GaussianBlur(img, (1, 1), 2)
h, w = img.shape[:2]

# Morphological gradient

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
gradient = cv2.morphologyEx(blur, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('Morphological gradient', gradient)

#Contours
thresh = cv2.threshold(img,150, 255,cv2.THRESH_BINARY_INV)[1]
cnts, h = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow('thresh', thresh)

I tried the histogram back projection method. It somewhat worked but it still shows some unwanted part of the image. I just want the stockpile to be shown in the result.

Here is the code and the resulting image:

# Original Image
orig_img = cv2.imread('Feature Extraction/soil_stockpile_test_image.png')
roi = cv2.imread('Feature Extraction/roi_soil.png')

# HSV Image
hsv_img = cv2.cvtColor(orig_img, cv2.COLOR_BGR2HSV)
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)

# Region of Interest
roi_hist = cv2.calcHist([hsv_roi], [0, 1], None, [180, 256], [0, 180, 0, 256])
mask = cv2.calcBackProject([hsv_img], [0, 1], roi_hist, [0, 180, 0, 256], 1)


# Remove Noise
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
mask = cv2.filter2D(mask, -1, kernel)
_, mask = cv2.threshold(mask, 210, 255, cv2.THRESH_BINARY)

# Merge and perform bitwise operation
mask = cv2.merge((mask, mask, mask))
result = cv2.bitwise_and(orig_img, mask)

#cv2.imshow('HSV Image', hsv_img)
#cv2.imshow('Region of Interest', roi)
#cv2.imshow('Mask', mask)
cv2.imshow('Result', result)

Result:

enter image description here

Edit 1:

After using the grab cut algorithm, with the following code, this is the result I obtained:

# Grab Cut Mask
img = cv2.imread('Feature Extraction/soil_stockpile_test_image.png')

# These params have been hardcoded. Need to be changed for every image.
top_left_x = 300
top_left_y = 150
bottom_right_x = 600
bottom_right_y = 350
Green_color = (0, 255, 0)

# Draw the rectangle
output = cv2.rectangle(img,
                (top_left_x, top_left_y),
                (bottom_right_x, bottom_right_y),
                color=Green_color, thickness=3)

#cv2.imwrite('Output_Image_with_Rectangle.jpg', output)
#cv2.imshow('Output Image with Rectangle', output)

# Grab Cut Mask
mask = np.zeros(img.shape[:2],np.uint8)

bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)

rect = (top_left_x, top_left_y, bottom_right_x, bottom_right_y)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)

mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
new_img = img*mask2[:,:,np.newaxis]

cv2.imwrite('Grab_Cut_img.jpg', new_img)
plt.imshow(new_img),plt.colorbar(),plt.show()

image description

But there is still some black part there. Can I resize this grab cut image? Also, How do i do that? Also, in the image, you can see that there is still some background. How do I suppress this?

I really need your help. Thanks.