how to mark the labels on image using watershed opencv - python

As this is the output from the watershed and I want to mark the labels like 1,2,3 etc on the regions identified. I have tried to use cv2.puttext as well by using cv2.boudingrect but the labels are not coming in the center of the region identified
for i in range(2, ret3+1):
a=0
b=0
mask = np.where(markers==i, np.uint8(255), np.uint8(0))
x,y,w,h = cv2.boundingRect(mask)
area = cv2.countNonZero(mask[y:y+h,x:x+w])
print ("Label %d at (%d, %d) size (%d x %d) area %d pixels" % (i,x,y,w,h,area))
# Visualize
color = np.uint8(np.random.random_integers(0, 0, 3)).tolist()
output[mask!=0] = color
cv2.putText(img2,'%d'%i,(int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 3.9, color, 15, cv2.LINE_AA)
plt.imshow(img2, cmap='jet')
plt.show()
Through the above code the generated labels are as follows
What i want is that to mark the labels 3,4,5 etc in the center of the objects identified by watershed.

You can find the center of each region like this:
markers = cv2.watershed(img, markers)
labels = np.unique(markers)
for label in labels:
y, x = np.nonzero(markers == label)
cx = int(np.mean(x))
cy = int(np.mean(y))
The result:
Complete example:
import cv2
import numpy as np
img = cv2.imread("water_coins.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# noise removal
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# sure background area
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# Finding sure foreground area
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers + 1
# Now, mark the region of unknown with zero
markers[unknown == 255] = 0
markers = cv2.watershed(img, markers)
labels = np.unique(markers)
for label in labels:
y, x = np.nonzero(markers == label)
cx = int(np.mean(x))
cy = int(np.mean(y))
color = (255, 255, 255)
img[markers == label] = np.random.randint(0, 255, size=3)
cv2.circle(img, (cx, cy), 2, color=color, thickness=-1)
cv2.putText(img, f"{label}", (cx, cy), cv2.FONT_HERSHEY_SIMPLEX, 0.35, color, 1, cv2.LINE_AA)
cv2.imwrite("out.jpg", img)

Erode every region independently with a structuring element that has the size of the region label. Then use any remaining pixel.
In some cases (tiny regions), no pixel at all will remain. You have two options
use a pixel from the "ultimate eroded";
use some location near the region and a leader line (but avoiding collisions is uneasy).
You can also work with the inner distances of the regions and pick pixels with maximum distance.

Related

How to measure coin widths using Python?

I followed the tutorial shown at OpenCV site.. How could I use the same example and extend it to detect coin widths ?
I know how I could use HoughCircles() and FindContour() python functions but this approach is more stable in noisy backgrounds.
I would like to extract the segmented coins and use circle/contour detection for width estimation. But I don't understand how I could extend this code.
import numpy as np
import cv2
from matplotlib import pyplot as plt
# https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_watershed/py_watershed.html
img_file_name = r'C:\Users\coins.jpg'
img = cv2.imread(img_file_name)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
#cv2.imshow("thresolded",thresh)
# noise removal
kernel = np.ones((6,6),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 3)
# sure background area
sure_bg = cv2.dilate(opening,kernel,iterations=3)
#cv2.imshow("dilate",sure_bg)
# Finding sure foreground area
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
cv2.imshow("dist_transform",sure_fg)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)
cv2.imshow("subtract",unknown)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers+1
# Now, mark the region of unknown with zero
markers[unknown==255] = 0
#markers = cv2.watershed(img,markers)
markers = cv2.watershed(img,markers)
img[markers == -1] = [0,255,0]
cv2.imshow("markers",img)
Here as I slightly changed your code:
import numpy as np
import cv2
import imutils
from matplotlib import pyplot as plt
img_file_name = 'coins.jpg'
img = cv2.imread(img_file_name)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# noise removal
kernel = np.ones((6,6),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 3)
# sure background area
sure_bg = cv2.dilate(opening,kernel,iterations=3)
# CHANGE
dist_transform = cv2.distanceTransform(thresh,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
# CHANGE
unknown = cv2.subtract(thresh,sure_fg)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers+1
# Now, mark the region of unknown with zero
markers[unknown==255] = 0
markers = cv2.watershed(img,markers)
Here the code that you can use:
# loop over the unique markers returned by the Watershed
# algorithm
num_coins = np.amax(markers) -1
coins_width = np.zeros(num_coins)
for marker in np.unique(markers):
# if the marker is -1, we are examining the borders
# if the marker is 1, we are examining the 'background'
# so simply ignore them
if marker <= 1:
continue
# otherwise, allocate memory for the marker region and draw
# it on the mask
mask = np.zeros(gray.shape, dtype="uint8")
mask[markers == marker] = 255
# detect contours in the mask and grab the largest one
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
largest_cnt = max(cnts, key=cv2.contourArea)
#
# First Way
#
# calculate the center of the contour
M = cv2.moments(largest_cnt )
x = int(M["m10"] / M["m00"])
y = int(M["m01"] / M["m00"])
# calculate the radius of the contour from area (I suppose it's a circle)
area = cv2.contourArea(largest_cnt)
radius = np.sqrt(area/3.14)
#
# Second Way
#
# draw a circle enclosing the object
# ((x, y), radius) = cv2.minEnclosingCircle(largest_cnt)
cv2.circle(img, (int(x), int(y)), int(radius), (0, 255, 0), 1)
cv2.putText(img, "#{}".format(marker-2), (int(x) - 10, int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1)
coins_width[marker-2] = 2* radius
print(coins_width)
cv2.imshow("markers",img)
The code is a modified version of the code in the article:
https://www.pyimagesearch.com/2015/11/02/watershed-opencv/

Open CV Watershed not segmenting oval objects properly

Attemping to create a way to process images to count different types of tablets. The following code has been working well for circular objects, however oval shapes are creating issues that I cant find a workaround for.
kernel = np.ones((5,5),np.uint8)
image = cv2.imread('sample.jpg')
shifted = cv2.GaussianBlur(image, (15, 15), 1)
shifted = cv2.pyrMeanShiftFiltering(shifted, 21, 51)
shifted = cv2.erode(shifted,kernel,iterations=1)
shifted = cv2.dilate(shifted,kernel,iterations=1)
cv2.imwrite("step1.jpg", shifted)
gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imwrite("step2.jpg", thresh)
thresh = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
cv2.imwrite("step3.jpg", thresh)
thresh = cv2.bitwise_not(thresh)
thresh = cv2.erode(thresh,kernel,iterations=1)
cv2.imwrite("step4.jpg", thresh)
D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, indices=False, min_distance=10,
labels=thresh)
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=thresh)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
for label in np.unique(labels):
if label == 0:
continue
mask = np.zeros(gray.shape, dtype="uint8")
mask[labels == label] = 255
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)
((x, y), r) = cv2.minEnclosingCircle(c)
cv2.circle(image, (int(x), int(y)), int(r), (0, 255, 0), 2)
cv2.putText(image, "#{}".format(label), (int(x) - 10, int(y)),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
cv2.imwrite("step5.jpg", image)
cv2.waitKey(0)
Image that is being used is :
https://imgur.com/a/1U49DeT
Output after filtering yields :
https://imgur.com/a/vXwrWlG
Any teaching points as to how to fix this would be greatly appreciated.
I think there is a better way to use the watershed operator.
It relies on having a good gradient, but if the images are similar to this one, you should be able to do this effectively. Also, there are very powerful edge detectors today, much better than the one I used on this demo.
import cv2
import numpy as np
import higra as hg
from skimage.segmentation import relabel_sequential
import matplotlib.pyplot as plt
def main():
img_path = "pills.jpg"
img = cv2.imread(img_path)
img = cv2.resize(img, (256, 256))
img = cv2.GaussianBlur(img, (9, 9), 0)
edges = cv2.Canny(img, 100, 100)
size = img.shape[:2]
graph = hg.get_4_adjacency_graph(size)
edge_weights = hg.weight_graph(graph, edges, hg.WeightFunction.mean)
tree, altitudes = hg.watershed_hierarchy_by_area(graph, edge_weights)
segments = hg.labelisation_horizontal_cut_from_threshold(tree, altitudes, 500)
segments, _, _ = relabel_sequential(segments)
print('The number of pills is ', segments.max() - 1)
plt.imshow(segments)
plt.show()
if __name__ == "__main__":
main()
Initially, I resize the image to speed up the computation and apply a blur to reduce the background gradient. I detect its edges (gradient) and create a graph with it as edge weights; then I compute the watershed hierarchy ordered by area and threshold it obtaining the connected component at that level, from this you can count the number of segments.

Normalizing curved lines to form a rectangle using opencv

I have an underwater camera that detects PVC frameworks as in Image 1. I've added random online water effects so it accumulates for the expected rough conditions.
I've tried two approaches:
Canny Edge Algorithm.
Multiple color conversions, smoothing and thresholding.
The most efficient result was the later's result.
My problem is that I'm having trouble preparing this result for further processing.
For easier processing, the result needs line-shaped with constant width as in this one for the rightmost part.
I tried Probabilistic Hough Line Transform to detect any lines but they all are too curved to be detected.
To extract the lines from the image, you could filter the horizontal and vertical lines after thresholding and draw rectangles with a constant width through the centers, then remove the small objects around the intersections:
import cv2
import numpy as np
from skimage.io import imread
from skimage.morphology import remove_small_objects
rgb = imread('https://i.stack.imgur.com/QPz8W.jpg')
# convert to HSV for thresholding
hsv = cv2.cvtColor(rgb, cv2.COLOR_RGB2HSV)
# threshold hue channel for purple tubes, value channel for blue tubes
thresh_hue = cv2.threshold(hsv[..., 0], 127, 255, cv2.THRESH_BINARY)[1]
thresh_val = cv2.threshold(hsv[..., 2], 200, 255, cv2.THRESH_BINARY)[1]
# combine purple tubes with blue tubes
thresh = thresh_hue | thresh_val
cv2.imwrite('threshold_result.png', thresh)
# morphologically close the gaps between purple and blue tubes
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8))
cv2.imwrite('closing_result.png', thresh)
# morphological opening with horizontal and vertical kernels
h_kernel = np.zeros((11, 11), dtype=np.uint8)
h_kernel[5, :] = 1
v_kernel = np.zeros((11, 11), dtype=np.uint8)
v_kernel[:, 5] = 1
h_tubes = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, h_kernel, iterations=6)
v_tubes = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, v_kernel, iterations=7)
cv2.imwrite('horizontal_tubes.png', h_tubes)
cv2.imwrite('vertical_tubes.png', v_tubes)
# find contours and draw rectangles with constant widths through centers
h_contours = cv2.findContours(h_tubes, cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)[0]
h_lines = np.zeros(thresh.shape, np.uint8)
for cnt in h_contours:
x, y, w, h = cv2.boundingRect(cnt)
y += int(np.floor(h / 2) - 4)
cv2.rectangle(h_lines, (x, y), (x + w, y + 8), 255, -1)
v_contours = cv2.findContours(v_tubes, cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)[0]
v_lines = np.zeros(thresh.shape, np.uint8)
for cnt in v_contours:
x, y, w, h = cv2.boundingRect(cnt)
x += int(np.floor(w / 2) - 4)
cv2.rectangle(v_lines, (x, y), (x + 8, y + h), 255, -1)
# combine horizontal and vertical lines
all_lines = h_lines | v_lines
cv2.imwrite('all_lines.png', all_lines)
# remove small objects around the intersections
xor = np.bool8(h_lines ^ v_lines)
removed = xor ^ remove_small_objects(xor, 350)
result = all_lines & ~removed * 255
cv2.imwrite('result.png', result)
threshold_result.png
closing_result.png
horizontal_tubes.png
vertical_tubes.png
all_lines.png
result.png

Optimizing image recognition of colored beads in openCV

After loads of reading and trying around i hope someone here can help me out with the final steps.
I'm about to use openCV for counting of 2 different colored objects.
I convert into an HSV image, define the boundaries for the 2 colors to get a mask with each color. Afterwards i use a kernel to smoothen the pic and correct holes.
At the end using watershed to identify the single beads in the picture.
The algorithm doesnt work too bad but is still to unprecise especially for the blue beads, closely touching objects and the wall regions (see maskb). I'd be very tahnkful for any tipps for improvement.
The amount in the picture are ~580 blue and ~1632 white beads.
My code is the following:
img = cv2.imread('xxx')
#set font
font= cv2.FONT_HERSHEY_SIMPLEX
# shift correction
shifted = cv2.pyrMeanShiftFiltering(img, 15, 30)
#hsv conversion
hsv = cv2.cvtColor(shifted, cv2.COLOR_BGR2HSV)
# define range of white color in HSV for brown background
lower_white = np.array([0, 0, 190])
upper_white = np.array([360, 255, 255])
maskw= cv2.inRange(hsv, lower_white, upper_white)
# define range of green color in HSV
lower_blue = np.array([0, 0, 0])
upper_blue = np.array([360, 255, 48])
maskb=cv2.inRange(hsv,lower_blue, upper_blue)
"""MASK CORRECTION"""
# corrects open lines and holes in picture -- closing doesnt work - opening leads to better result - 5,5 is array
kernelOpen=np.ones((4,4))
kernelClose=np.ones((5,5))
#morphology mask white
maskOpenw=cv2.morphologyEx(maskw,cv2.MORPH_OPEN,kernelOpen)
maskClosew=cv2.morphologyEx(maskOpenw,cv2.MORPH_CLOSE,kernelClose)
#morphology mask blue
maskOpenb=cv2.morphologyEx(maskb,cv2.MORPH_OPEN,kernelOpen)
maskCloseb=cv2.morphologyEx(maskOpenb,cv2.MORPH_CLOSE,kernelClose)
""" FOR WHITE!!! - min distance factor to play"""
# compute the exact Euclidean distance from every binary
# pixel to the nearest zero pixel, then find peaks in this
# distance map
D = ndimage.distance_transform_edt(maskOpenw)
localMax = peak_local_max(D, indices=False, min_distance=9,
labels=maskOpenw)
# perform a connected component analysis on the local peaks,
# using 8-connectivity, then appy the Watershed algorithm
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=maskOpenw)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
# loop over the unique labels returned by the Watershed
# algorithm
for label in np.unique(labels):
# if the label is zero, we are examining the 'background'
# so simply ignore it
if label == 0:
continue
# otherwise, allocate memory for the label region and draw
# it on the mask
mask = np.zeros(maskOpenw.shape, dtype="uint8")
mask[labels == label] = 255
# detect contours in the mask and grab the largest one
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)
# draw a circle enclosing the object
((x, y), r) = cv2.minEnclosingCircle(c)
cv2.circle(img, (int(x), int(y)), int(r), (0, 255, 0), 2)
# cv2.putText(img, "#{}".format(label), (int(x) - 10, int(y)),
# cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
""" FOR Blue!!!"""
# compute the exact Euclidean distance from every binary
# pixel to the nearest zero pixel, then find peaks in this
# distance map
D = ndimage.distance_transform_edt(maskb)
localMax = peak_local_max(D, indices=False, min_distance=9,
labels=maskOpenb)
# perform a connected component analysis on the local peaks,
# using 8-connectivity, then appy the Watershed algorithm
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=maskOpenb)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
# loop over the unique labels returned by the Watershed
# algorithm
for label in np.unique(labels):
# if the label is zero, we are examining the 'background'
# so simply ignore it
if label == 0:
continue
# otherwise, allocate memory for the label region and draw
# it on the mask
mask = np.zeros(maskOpenb.shape, dtype="uint8")
mask[labels == label] = 255
# detect contours in the mask and grab the largest one
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)
# draw a circle enclosing the object
((x, y), r) = cv2.minEnclosingCircle(c)
cv2.circle(img, (int(x), int(y)), int(r), (0, 255, 0), 2)
#cv2.putText(img, "#{}".format(label), (int(x) - 10, int(y)),
# cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
# show picture
cv2.imshow("image", img)
cv2.waitKey()
Thanks in advance,
Jannik
EDIT: I tried to do a distance transformation for the blue beads which leads to the following results:
Distance Transformation
The added Code:
# sure background area
sure_bg = cv2.dilate(maskb,kernelOpen,iterations=5)
cv2.imshow("surebg", sure_bg)
# Finding sure foreground area
dist_transform = cv2.distanceTransform(maskb,cv2.DIST_L2,3)
ret, sure_fg = cv2.threshold(dist_transform,0.14*dist_transform.max(),255,0)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
cv2.imshow("surefg", sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
cv2.imshow("unknown", unknown)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers+1
# Now, mark the region of unknown with zero
markers[unknown==255] = 0
markers = cv2.watershed(img,markers)
img[markers == -1] = [0,0,255]
print(ret)
cv2.imshow("img", img)
The Marking of the beads works quite well even some regions are unprecise.If i understood correct the "ret" value gives me the count of objects marked. Anyone any idea to further reach a precise counting?

drawing a disk by analyzing neighbors pixel intensity

The picture and code below is a toy example that should reflect an experiment I am running.
I would like to extract a disk corresponding to the boundary in the picture where the pixels intensities are the same or similar (in this example the bluish disk)
Using HoughCircles procedure, I can extract the center of the most probable circle of the picture.
From there I would like to probe 360° from the center at the various radius (higher or lower) from the detected center to define the boundaries (max radius and min radius) of the bluish color in the picture below.
How can I do that?
I try to analyze the histogram by applying multiple masks without success.
The green circle is the one detected with HoughCircles, the blue and red circle are the +/- 15% radius circle.
import cv2
import numpy as np
from matplotlib import pyplot as plt
image = cv2.imread("./picture.jpg")
output = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 2, 800,
param1=300,
param2=1,
minRadius=100,
maxRadius=0)
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")
output = image.copy()
# loop over the (x, y) coordinates and radius of the circles
for (x, y, r) in circles:
# draw the circle in the output image, then draw a rectangle
# corresponding to the center of the circle
cv2.circle(output, (x, y), r, (0, 255, 0), 2)
cv2.rectangle(output, (x - 2, y - 2), (x + 2, y + 2), (0, 128, 255), -1)
# create the mask and explore histograms
# height,width,depth = output.shape
# mask = np.zeros((height,width), np.uint8)
# cv2.circle(mask, (x, y), int(round(r - (r* .15))), 1, thickness=-1)
# output = cv2.bitwise_and(output, output, mask=mask)
# hist_full = cv2.calcHist([output],[0],None,[256],[0,256])
# hist_mask = cv2.calcHist([output],[0],mask,[256],[0,256])
# plt.hist(image.ravel(),256,[0,256]); plt.show()
# plt.plot(hist_full),
# plt.plot(hist_mask)
# plt.xlim([0,256])
# plt.show()
cv2.circle(output, (x, y), int(round(r * 1.15)), (255, 0, 0), 2)
cv2.circle(output, (x, y), int(round(r - (r* .15))), (0, 0, 255), 2)
# show the output image
cv2.imshow("output", np.hstack([image, output]))
cv2.waitKey(0)
I resized the disk image, because the origin is too large. So you may modify the parameters in the function.
The source:
I found in S(HSV), the disk is more clear, so I did canny in "S".
The result:
You can reproduce the result using the code.
#!/usr/bin/python3
# 2017.11.21 21:03:09 CST
# 2017.11.22 23:21:42 CST
# 2017.11.25 16:32:46 CST
import cv2
import numpy as np
img = cv2.imread("disk2.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
## Canny edge in S(HSV)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)
canny = cv2.Canny(s, 30, 200)
## The inner circle using gray
circles1 = cv2.HoughCircles(gray, method = cv2.HOUGH_GRADIENT,
dp = 2, minDist = 100,
param1=200, param2=100,
minRadius=80, maxRadius=200)
## The outer circle using canny
circles2 = cv2.HoughCircles(canny, method = cv2.HOUGH_GRADIENT,
dp = 2, minDist = 100,
param1=200, param2=100,
minRadius=200, maxRadius=0)
x1,y1, r1 = circles1[0][0]
x2,y2, r2 = circles2[0][0]
## create the mask
mask = np.zeros_like(canny)
cv2.circle(mask, (x2, y2), r2, 255, -1)
cv2.circle(mask, (x1, y1), r1, 0, -1)
## crop
imask = mask > 0
masked = np.zeros_like(img)
masked[imask] = img[imask]
cv2.imshow("canny", canny)
cv2.imshow("mask", mask)
cv2.imshow("croped", masked)
cv2.waitKey()
cv2.destroyAllWindows()

Categories