Python OpenCV顺时针排序等高线

2024-04-19 22:10:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在组装一个图像处理工具,用图像跟踪零件的变形。该零件具有矩形标记,可通过图像分割和cv2.findContours功能进行检测。轮廓中心然后用于计算距离和弯曲半径。一切似乎都很好,但我发现轮廓没有按照我在查看结果时希望的方式进行排序。 零件反复弯曲,轮廓定位为圆形

我发现这篇文章描述了横向和纵向排序:

https://www.pyimagesearch.com/2015/04/20/sorting-contours-using-python-and-opencv/

有人知道如何按顺时针方向排列轮廓吗

代码如下

import os
import exifread
import cv2
import numpy as np
import scipy
from matplotlib import pyplot as plt
import imutils
import pandas as pd


#---------- INPUT ----------

# Define the image filename
img_filename = 'frame397.jpg'

img_path = img_filename

# Define values for cropping
x = 0
y = 200
w = 1200
h = 800

# Define color values for segmentation
# the values can be probed with GIMP

h1 = 0
s1 = 70
v1 = 120
h2 = 255
s2 = 255
v2 = 255

red_lower = np.array([h1,s1,v1])
red_upper = np.array([h2,s2,v2])

# Define desired area size
# desired area size is pixel count - use GIMP for probe
s1 = 500
s2 = 10000


#---------- PROCESS IMAGES ----------

# Create an empty dataframe for storing results
# in shape of (image_name,time,angle,angle_smooth,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11)

# Define the results dataframe shape and column names
results_df = pd.DataFrame(columns=['image_name','alpha','r1','r2','r3','r4','r5','r6','r7','r8','r9','r10','r11',
                                   'center_dist1', 'center_dist2','center_dist3','center_dist4',
                                   'center_dist5','center_dist6','center_dist7','center_dist8',
                                   'center_dist9','center_dist10','center_dist11'])

# Open image, make it black and white and find contours
img = cv2.imread(img_path)
crop = img[y:y+h, x:x+w]
blur = cv2.blur(crop,(2,2))
hsv = cv2.cvtColor(blur,cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, red_lower, red_upper)
mask_copy = mask.copy()
cnts = cv2.findContours(mask_copy,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
#print cnts
x = []
y = []

# Loop through contours, calculate the centers and prepare the
#contours and contour centers display

#define the font for the text on the image
font = cv2.FONT_HERSHEY_SIMPLEX

for cnt in cnts:
    area = cv2.contourArea(cnt)
    moment = cv2.moments(cnt)
    if s1<area<s2:
        print area
        c_x = int(moment["m10"]/moment["m00"])
        c_y = int(moment["m01"]/moment["m00"])
        #draw contours
        cv2.drawContours(crop, cnt, -1, (0,255,0),3)
        #draw a circle in the center of every contour, -1 is for thickness, this means
        #that the cirlce will get filled in
        cv2.circle(crop, (c_x,c_y), 10, (0,255,0),-1)
        #display center coordinates on the image
        string = str(c_x) + ',' + str(c_y)
        cv2.putText(crop,string,(c_x,c_y),font,0.5,(255,255,255),2)
        x.append(float(c_x))
        y.append(float(c_y))
        print (c_x, c_y)

print x
print y

# Display image
cv2.namedWindow('Contours', cv2.WINDOW_NORMAL)
cv2.resizeWindow('Contours', 1200,900)
cv2.imshow('Contours', crop)

# Wait for windows closing
cv2.waitKey() & 0xFF
cv2.destroyAllWindows

图片如下: enter image description here


Tags: andthecropimageimportimgforarea
1条回答
网友
1楼 · 发布于 2024-04-19 22:10:58

我使用openCV的MineConclosingCircle将圆“拟合”到点(它实际上不是拟合,但足以在标记的曲率内找到点)。用从质心到圆心的角度标记每个轮廓,给了我一组可以排序的角度

enter image description here

import cv2
import numpy as np
import math

# 2d distance
def dist2D(one, two):
    dx = one[0] - two[0];
    dy = one[1] - two[1];
    return math.sqrt(dx*dx + dy*dy);

# angle between three points (the last point is the middle)
def angle3P(p1, p2, p3):
    # get distances
    a = dist2D(p3, p1);
    b = dist2D(p3, p2);
    c = dist2D(p1, p2);

    # calculate angle // assume a and b are nonzero
    # (law of cosines)
    numer = c**2 - a**2 - b**2;
    denom = -2 * a * b;
    if denom == 0:
        denom = 0.000001;
    rads = math.acos(numer / denom);
    degs = math.degrees(rads);

    # check if past 180 degrees
    if p1[1] > p3[1]:
        degs = 360 - degs;
    return degs;

# load image
img = cv2.imread("slinky.jpg");

# rescale
scale = 0.5;
h, w = img.shape[:2];
h = int(h * scale);
w = int(w * scale);
img = cv2.resize(img, (w,h));

# change color space
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB);
l,a,b = cv2.split(lab);

# threshold
thresh = cv2.inRange(a, 140, 255);

# get rid of little dots
kernel = np.ones((3,3),np.uint8)
thresh = cv2.erode(thresh,kernel,iterations = 1);
thresh = cv2.dilate(thresh,kernel, iterations = 1);

# contours
_, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);

# get centroids
centroids = [];
centers = [];
for con in contours:
    m = cv2.moments(con);
    cx = int(m['m10'] / m['m00']);
    cy = int(m['m01'] / m['m00']);
    centers.append([cx, cy]);
    centroids.append([[cx, cy], con]);
    img = cv2.circle(img, (cx, cy), 10, (0,0,255), -1);

# find circle around points
# NOTE: this doesn't "fit" a circle to the points
# I'm just using this to find a "good enough" center 
# that's in the direction of the curve
numped = np.array(centers);
(x, y), radius = cv2.minEnclosingCircle(numped);
img = cv2.circle(img, (int(x), int(y)), int(radius), (255,0,0), 2);
middle = [x,y];
offshoot = [x + 100, y];

# get angles
angles = [];
for cen in centroids:
    center, contour = cen;
    angle = angle3P(center, offshoot, middle);
    angles.append([angle, center, contour]);

# sort by angle
final = sorted(angles, key = lambda a: a[0], reverse = True);

# pull out just the contours
contours = [clump[2] for clump in final];

# draw contours in order
marked = img.copy();
counter = 0;
for con in contours:
    cv2.drawContours(marked, [con], -1, (0, 255, 0), 2);
    cv2.imshow("marked", marked);
    cv2.imwrite("marking_seq/" + str(counter) + ".png", marked);
    counter += 1;
    cv2.waitKey(0);

# show
cv2.imshow("orig", img);
cv2.imshow("a", a);
cv2.imshow("thresh", thresh);
cv2.waitKey(0);

相关问题 更多 >