3

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

nathancy
  • 42,661
  • 14
  • 115
  • 137
hawxeye
  • 99
  • 8
  • 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). –  Jul 13 '19 at 14:38
  • 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 edges – hawxeye Jul 14 '19 at 18:47
  • 1
    See misconception 2. –  Jul 14 '19 at 19:26
  • 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 Aug 01 '19 at 01:07
  • 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 Aug 02 '19 at 10:51

1 Answers1

4

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()

nathancy
  • 42,661
  • 14
  • 115
  • 137
  • 3
    beautiful result – lucians Jul 11 '19 at 21:17
  • This answers one part, and what about the internal diagnols of the bit. how can they be detected? – hawxeye Jul 11 '19 at 23:24
  • 1
    One idea is to extract the ROI of the drill bit since we have the contour and from here maybe do color thresholding to extract the darker areas. You could then use Canny edge detection to find the contours of the diagonals and use additional filtering such as contour area to ensure that only the diagonals are grabbed. Finally mask that all back onto the original image – nathancy Jul 12 '19 at 01:37
  • I think i got your point, i will try it but if you could show me the result like the one you already did it will be much easier. – hawxeye Jul 12 '19 at 02:23