0

Hi I am not very proficient in coding but I am trying to find the length and width of an image of a irregular shaped object (crystals in this case)

from scipy.spatial import distance as dist
import cv2
import imutils
from imutils import perspective
from imutils import contours

image = cv2.imread(path)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
# perform edge detection, then perform a dilation + erosion to
# close gaps in between object edges
edged = cv2.Canny(gray, 50, 100)
edged = cv2.dilate(edged, None, iterations=1)
edged = cv2.erode(edged, None, iterations=1)
# find contours in the edge map
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# sort the contours from left-to-right and initialize the
# 'pixels per metric' calibration variable
(cnts, _) = contours.sort_contours(cnts)
pixelsPerMetric = None
for c in cnts:
# if the contour is not sufficiently large, ignore it
if cv2.contourArea(c) < 50:
    continue
# compute the rotated bounding box of the contour


orig = image.copy()
x,y,w,h = cv2.boundingRect(c)
box = cv2.rectangle(orig,(x,y),(x+w,y+h),(0,255,0),2)
tltrX, tltrY) =((x+w/2),y)
(blbrX, blbrY) = ((x+w/2),y+h)
# compute the midpoint between the top-left and top-right points,
# followed by the midpoint between the top-righ and bottom-right
(tlblX, tlblY) = (x,(y+h/2))
(trbrX, trbrY) = (x+w,(y+h/2))
# draw the midpoints on the image
cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
# draw lines between the midpoints
cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),(255, 0, 255), 2)
cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),(255, 0, 255), 2)
# compute the Euclidean distance between the midpoints
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))

small crystal

large crystals

large crystals

As you can see for small crystals it does reasonably well but still not up to the standard i require it, for large crystal it gets it all wrong. I understand that the code leads to several bounding boxes for one image, I have no problem with that just need one that is accurate. Is there a way to make the bounding boxes fit better? I tried distinguishing the image from the background further as detailed here :Irregular shape detection and measurement in python opencv But it still didn't help.

EnYou
  • 21
  • 4

0 Answers0