How do I pass a line through the center of a contour? I have the center coordinates of my contour.
Asked
Active
Viewed 6,395 times
1
-
a line has two points i.e. start(x,y) and stop(x,y). So where do you want your line to start and where should it stop? Do you want the line to start from boundary, pass through center and end at boundary? Please ellaborate – Devashish Prasad Jul 20 '18 at 05:53
-
I have put a rectangle around a contour.I need to put a line horizontally at the center of that rectangle.Like cutting the rectagnle into two halves.How do I get the coordinates of the four corners of that rectangle drawn? – Anees Jul 20 '18 at 10:59
1 Answers
5
This is how you solve this question -
Original image -
Result image -
You first need to do basic filtering and find the contour. Then -
1) Find out the area of contour (minAreaRect)
2) Extract points from the contour (BoxPoints)
3) Convert it to a numpy array (np.array)
4) Order the points (perspective.order_points)
5) Take out Top-left, Top-right, Bottom-right and Bottom-left(tl, tr, br, bl) = box (Line 52)
6) Calculate the midpoints ( (point1 + point2) / 2)
7) Draw the lines (line 76)
Here is the code for it
# import the necessary packages
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)
# load the image, convert it to grayscale, and blur it slightly
image = cv2.imread("test.png")
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 = cnts[0] if imutils.is_cv2() else cnts[1]
# loop over the contours individually
for c in cnts:
# This is to ignore that small hair countour which is not big enough
if cv2.contourArea(c) < 1000:
continue
# compute the rotated bounding box of the contour
box = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
box = np.array(box, dtype="int")
# order the points in the contour such that they appear
# in top-left, top-right, bottom-right, and bottom-left
# order, then draw the outline of the rotated bounding
# box
box = perspective.order_points(box)
# draw the contours on the image
orig = image.copy()
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 3)
# unpack the ordered bounding box, then compute the midpoint
# between the top-left and top-right coordinates, followed by
# the midpoint between bottom-left and bottom-right coordinates
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
# compute the midpoint between the top-left and top-right points,
# followed by the midpoint between the top-righ and bottom-right
(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)), 5, (255, 0, 0), -1)
cv2.putText(orig, "({},{})".format(blbrX, blbrY), (int(blbrX - 50), int(blbrY - 10) - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)
cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
cv2.putText(orig, "({},{})".format(tlblX, tlblY), (int(tlblX - 50), int(tlblY - 10) - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)
cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
cv2.putText(orig, "({},{})".format(trbrX, trbrY), (int(trbrX - 50), int(trbrY - 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)),
(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))
# loop over the original points
for (xA, yA) in list(box):
# draw circles corresponding to the current points and
cv2.circle(orig, (int(xA), int(yA)), 5, (0,0,255), -1)
cv2.putText(orig, "({},{})".format(xA, yA), (int(xA - 50), int(yA - 10) - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)
# show the output image, resize it as per your requirements
cv2.imshow("Image", orig)
cv2.waitKey(0)

Devashish Prasad
- 1,227
- 1
- 13
- 25