Related
I've got images like this one:
I need to detect the center of this circular element:
(More precisely - I'm looking for the midpoint of the circular element)
Currently my code detect the mold (the plastic circle that holds the circular element) and select the rectangle ROI to focus the image into the relevant area:
import cv2
import imutils
import numpy as np
if __name__ == "__main__":
image = cv2.imread('Dart - Overview Image - with Film.bmp')
img = imutils.resize(image, width=700)
image = img
output = image.copy()
roi = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# cv2.imshow("Gray", gray)
# cv2.waitKey(0)
# detect circles in the image
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100)
# ensure at least some circles were found
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")
# 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)
roi = roi[y - r: y + r, x - r: x + r]
cv2.imshow("img", roi)
cv2.waitKey(0)
This will show this image:
Now, I'm trying to find the midpoint of the circular element inside this ROI image by detecting the circular element but It's challenged for me, I've try this methods:
gray_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray_roi, (3, 3), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_OTSU + 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]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
(x, y), radius = cv2.minEnclosingCircle(c)
cv2.circle(roi, (int(x), int(y)), int(radius), (35, 255, 12), 3)
cv2.circle(roi, (int(x), int(y)), 1, (35, 255, 12), 2)
print(x, y)
break
# Find Canny edges
edged = cv2.Canny(roi, 30, 121, apertureSize=3, L2gradient=True)
cv2.waitKey(0)
# Finding Contours
# Use a copy of the image e.g. edged.copy()
# since findContours alters the image
contours, hierarchy = cv2.findContours(edged,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.imshow('Canny Edges After Contouring', edged)
cv2.waitKey(0)
And got this output:
I've also tried to change the threshold parameters in the cv2.Canny function but it's didn't give me better results.
Thanks a lot!
I am having a problem when I change the size of the image. Then the proportions of the line no longer match those of the image, i.e. the line will become smaller than expected.
Any idea how I can resize the line proportionally equal to the image?
Here is the original image:
Here is the result that I want:
But this is the result that I get after resizing (it gives the same value at second picture):
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import imutils
import cv2
# Method to find the mid point
def midpoint(ptA, ptB):
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
img = cv2.imread('banana4.jpg')
# Gaussian blur
blur1 = cv2.GaussianBlur(img,(3,3),1)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_blue = np.array([5, 25, 25])
upper_blue = np.array([70, 255, 255])
thresh = cv2.inRange(hsv, lower_blue, upper_blue)
# Find contours and sort for largest contour
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
x, y, w, h = cv2.boundingRect(c)
box = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
box = np.array(box, dtype="int")
box = perspective.order_points(box)
orig = img.copy()
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 3)
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# draw and write the midpoints on the image
cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
cv2.putText(orig, "({},{})".format(tltrX, tltrY), (int(tltrX - 50), int(tltrY - 10) - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)
cv2.circle(orig, (int(blbrX), int(blbrY-90)), 5, (255, 0, 0), -1)
cv2.putText(orig, "({},{})".format(blbrX, blbrY-90), (int(blbrX - 50), int(blbrY - 10) - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)
# draw lines between the midpoints
cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY-90)),
(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))
cv2.imshow("Image", orig)
break
how to draw a straight line in contour features in Opencv python and calculate in mm(millimeter). Im using also the cv2.line but it not giving me an accurate straight.
Im just using a paint for this green line
hsv = cv2.cvtColor(6.jpg, cv2.COLOR_BGR2HSV)
lower_blue = np.array([5, 25, 25])
upper_blue = np.array([70, 255, 255])
thresh = cv2.inRange(hsv, lower_blue, upper_blue)
imask = thresh > 0
green = np.zeros_like(frame, np.uint8)
green[imask] = frame[imask]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
x, y, w, h = cv2.boundingRect(c)
# Draw rectangle
cv2.rectangle(green, (x, y), (x + w, y + h), (36, 255, 12), 2)
cv2.putText(green, "w={},h={}".format(w, h), (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (36, 255, 12), 2)
# Draw contours
cv2.drawContours(green, [c], -1, (0, 255, 255), 3)
break
I ran the following code to create a rectangle contour:
#import the necessary packages
import argparse
import imutils
import cv2
import numpy as np
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
help="path to the input image")
args = vars(ap.parse_args())
# load the image, convert it to grayscale, blur it slightly, and threshold it
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
# threshold the image, then perform a series of erosions + dilations to remove any small regions of noise
thresh = cv2.threshold(gray, 45, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.erode(thresh, None, iterations=2)
thresh = cv2.dilate(thresh, None, iterations=2)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# Find the index of the largest contour
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)
I would like to find the center line and center point of the rectangular contour. Please advise.
As you already have (x, y, w, h) of the desired contour using x,y,w,h = cv2.boundingRect(cnt) in above code, so center of the vertical mid line can be given by (x+w//2, y+h//2) and vertical line can be drawn using below code:
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
# center line
cv2.line(image, (x+w//2, y), (x+w//2, y+h), (0, 0, 255), 2)
# below circle to denote mid point of center line
center = (x+w//2, y+h//2)
radius = 2
cv2.circle(image, center, radius, (255, 255, 0), 2)
output:
Since you already have the bounding box, you can use cv2.moments() to find the center coordinates. This gives us the centroid (i.e., the center (x, y)-coordinates of the object)
M = cv2.moments(cnt)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
The center point is simply (cX, cY) and you can draw this with cv2.circle()
cv2.circle(image, (cX, cY), 5, (36, 255, 12), -1)
Similarly, we can draw the center line using cv2.line() or Numpy slicing
cv2.line(image, (x + int(w/2), y), (x + int(w/2), y+h), (0, 0, 255), 3)
image[int(cY - h/2):int(cY+h/2), cX] = (0, 0, 255)
import imutils
import cv2
import numpy as np
# load the image, convert it to grayscale, blur it slightly, and threshold it
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
# threshold the image, then perform a series of erosions + dilations to remove any small regions of noise
thresh = cv2.threshold(gray, 45, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.erode(thresh, None, iterations=2)
thresh = cv2.dilate(thresh, None, iterations=2)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# Find the index of the largest contour
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
M = cv2.moments(cnt)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
cv2.circle(image, (cX, cY), 5, (36, 255, 12), -1)
# To draw line you can use cv2.line or numpy slicing
cv2.line(image, (x + int(w/2), y), (x + int(w/2), y+h), (0, 0, 255), 3)
# image[int(cY - h/2):int(cY+h/2), cX] = (36, 255, 12)
# show the output image
cv2.imshow("Image", image)
cv2.imwrite("Image.png", image)
cv2.waitKey(0)
I try to detect forms in cytology image and I get this result enter image description here my input image is enter image description here But My result does not see good can anyone help me ???
My stage was,
Color image by (COLORMAP_HOT)
Convert to grayscal image
Apply the canny filter
Find count
Test the contour
and i use python3.5 and opencv3
my code :
#!/usr/bin/env python
import cv2
import numpy as np
from pyimagesearch.shapedetector import ShapeDetector
import argparse
import imutils
from scipy import ndimage
import math
import matplotlib.pyplot as plt
if __name__ == '__main__' :
im = cv2.imread("23.png")
#im_out = np.zeros((670, 543, 3), np.uint8);
#resized = imutils.resize(im, width=300)
#ratio = im.shape[0] / float(resized.shape[0])
#coloration
im_color = cv2.applyColorMap(im, cv2.COLORMAP_HOT)
imgg = im_color[:, :, 1]
#cv2.putText(im_color, colormap_name(k), (30, 180), cv2.FONT_HERSHEY_DUPLEX, 0.5, (255, 255, 255),1);
im_out = im_color
gray = cv2.cvtColor(im_color, cv2.COLOR_RGB2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
canny = cv2.Canny(blurred, 120, 200)
kernel = np.ones((5,5),np.uint8)
#morph
dilation = cv2.dilate(canny,kernel,iterations = 1)
erosion = cv2.erode(dilation,kernel,iterations = 1)
dilation = cv2.dilate(erosion,kernel,iterations = 1)
erosion = cv2.erode(dilation,kernel,iterations = 1)
blurred = cv2.GaussianBlur(erosion, (3, 3), 0)
canny = cv2.Canny(blurred, 200, 200)
cv2.imshow("dilation", dilation)
cv2.imshow("canny", canny)
cv2.imshow("erosion", erosion)
#(thresh, im_bw) = cv2.threshold(im_gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv2.imshow("im_out", im_out);
cv2.imshow("gray ", gray);
#contour
cnts = cv2.findContours(canny, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
# loop over the contours
for c in cnts:
M = cv2.moments(c)
if(M["m00"]==0):M["m00"]=1
cX = int((M["m10"] / M["m00"]))
cY = int((M["m01"] / M["m00"]))
#shape = detect(c)
c = c.astype("float")
c = c.astype("int")
#cv2.drawContours(im, [c], -1, (0, 255, 0), 2)
#cv2.putText(im, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255,0,0), 2)
area = cv2.contourArea(c)
perimeter = cv2.arcLength(c,True)
M = cv2.moments(c)
# initialize the shape name and approximate the contour
shape = " "
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.05 * peri, True)
(x, y, w, h) = cv2.boundingRect(approx)
area = cv2.contourArea(c)
radius = w/2
if len(approx) == 3:
shape = ""
# if the shape has 4 vertices, it is either a square or
# a rectangle
elif len(approx) == 4:
if (M['m00']==0):
M['m00']=1
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
# compute the bounding box of the contour and use the
# bounding box to compute the aspect ratio
#(x,y) be the top-left coordinate of the rectangle and (w,h) be its width and height.
(x, y, w, h) = cv2.boundingRect(approx)
print ("area",area,"perimeter",perimeter,"cx",cx,"cy",cy,"x",x,"y", y,"w", w, "h",h)
#fichier.write("area",area,"perimeter",perimeter,"cx",cx,"cy",cy)
print (sep="\n")
ar = w / float(h)
shape = "square" if ar >= 0.95 and ar <= 1.05 else "rectangle"
cv2.drawContours(im, [c], -1, (255, 0, 0), 2)
cv2.putText(im, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255,0,0), 2)
# if Cystine>6
elif len(approx) == 6:
if (M['m00']==0):
M['m00']=1
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print ("area",area,"perimeter",perimeter,"cx",cx,"cy",cy)
print (sep="\n")
shape = "HEXA"
cv2.drawContours(im, [c], -1, (255, 0, 0), 2)
cv2.putText(im, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255,0,0), 2)
# otherwise, we assume the shape is a circle
elif (abs(1 - (float(w)/h))<=2 and abs(1-(area/(math.pi*radius*radius)))<=0.2):
if (M['m00']==0):
M['m00']=1
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print ("area",area,"perimeter",perimeter,"cx",cx,"cy",cy)
print (sep="\n")
shape = "circle"
cv2.drawContours(im, [c], -1, (255,0, 0), 2)
cv2.putText(im, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255,0, 0), 2)
# show the output image
cv2.imshow("Image", im)
cv2.waitKey(0);