3
votes

I am new to OpenCV and python, so kindly help me like a 12 grader. My problem is that I want to detect the right threshold or edge of the drill bit for measurement but what I have done gives a lot of noise in the image due to which I cannot find the correct contour of the object.

I have tried removing glare in the image then histogram equalization after which I tried adaptive thresholding.

gray=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
h,s,v=cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV))

bgi=cv2.GaussianBlur(gray, (3, 3), 1.0)
rn_gr = cv2.fastNlMeansDenoising(bgi,None,10,7,21)

equ = cv2.equalizeHist(rn_gr)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(rn_gr)

nonSat = s < 40
disk = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))    
nonSat = cv2.erode(nonSat.astype(np.uint8), disk) 
v2 = v.copy()    
v2[nonSat == 0] = 0;  
glare = v2 > 200;
glare = cv2.dilate(glare.astype(np.uint8), disk);
glare = cv2.dilate(glare.astype(np.uint8), disk);    
corrected = cv2.inpaint(img, glare, 5, cv2.INPAINT_NS)
object=corrected[485:1665,225:335]
gray_co=cv2.cvtColor(object, cv2.COLOR_BGR2GRAY)
bgi_co=cv2.GaussianBlur(gray_co, (3, 3), 1.0)
rn_gr_co = cv2.fastNlMeansDenoising(bgi_co,None,10,7,21)
cl2 = clahe.apply(rn_gr_co)

v=np.median(cl2)
lower=int(max(0,(1.0-sigma)*v))
upper=int(min(255,(1.0+sigma)*v))
print(lower,upper)
edged = cv2.Canny(cl2,lower,upper)
th3_o = cv2.adaptiveThreshold(obj,upper,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
        th3_o=~th3_o

#kernel = np.ones((5,5),np.uint8)
kernel=cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
morph = cv2.morphologyEx(th3_o, cv2.MORPH_GRADIENT, kernel)
closing = cv2.morphologyEx(th3_o, cv2.MORPH_CLOSE, kernel)
opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, kernel)

contours_o, hierarchy = cv2.findContours(th3_o,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
for cnt_o in contours_o:
   epsilon = 0.1*cv2.arcLength(cnt_o,True)
   approx = cv2.approxPolyDP(cnt_o,epsilon,True)
   con_o = cv2.drawContours(th3_o, contours_o, -1, (0,255,0), 3)
plt.imshow(con_o)
plt.show()

my expected result should look like the pic I draw with boundaries required image but what I am getting is something like this not desired image

1
There are two common misconceptions in image processing: 1) edge detection works. It does not ! Binarization/contour following sometimes work. 2) an algorithm can guess what you have in mind (for instance selecting just the internal edges that you want).Yves Daoust
how can one determine the internal edges after binarization of image like the diagnols in the above image. like is there a pruning algorithm which finds only the conected loop edgeshawxeye
See misconception 2.Yves Daoust
To what accuracy are you trying to measure the edge? How do you know the true dimensions of the drill bit? Are you trying to measure according to some industrial standard? Assuming you can find the image edge accurately enough, you'll run into problems with optics. Even with backlighting to render the part dark on a light background, the part diameter will appears slightly smaller than the true dimension.Rethunk
I am trying to reach the accuracy of 1/10 of a mm. I have calculated the true dimensions using the vernier caliper. yes, I am trying to measure according to industrial standard. What kind of optic problems? but I think I have calibrated the camera for lens distortion. what do you suggest?hawxeye

1 Answers

4
votes

I think you're using too many operations and overthinking the approach to detecting the contours. You're using too many sequential operations without realizing the goal of each step. Typically, preprocessing is done on the image to remove noise or smooth out images (Gaussian/median/bilateral blur). Then some sort of binary segmentation is done on the image to isolate contours (thresholding, Canny edge detection). From here, morphological transformations can be done to further filter or enhance such as eroding or dilating. Then you can find contours and do additional filtering (contour area, proximity, aspect ratio). For this problem, the idea is to keep it simple with a strategic approach in order to isolate the outer contour


Here's a potential approach

  • Convert to grayscale and median blur image to remove noise and smooth image
  • Threshold image
  • Find contours
import cv2

image = cv2.imread('1.jpg')

blur = cv2.medianBlur(image, 7)
gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray,160,255, cv2.THRESH_BINARY_INV)[1]

cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

for c in cnts:
    cv2.drawContours(image, [c], -1, (36, 255, 12), 2)

cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.imwrite('image.png', image)
cv2.waitKey()