如何使用python以特定顺序对圈子进行编号?

时间:2017-05-03 07:42:51

标签: python opencv numbers circleimage

我想从图像中获取每个圆圈的阴影值。

  1. 我尝试使用HoughCircle检测圈子。
  2. 我得到了每个圆圈的中心。
  3. 我把文字(圆圈号码)放在一个圆圈里。
  4. 我设置像素子集以获取着色值并计算平均着色值。
  5. 我想以CSV格式获取圆圈数,中心坐标和平均着色值的结果。
  6. 但是,在第3步中,圈数是随机分配的。所以,很难找到圈数。

    如何对序列中的圆圈进行编号?

    enter image description here

    # USAGE
    # python detect_circles.py --image images/simple.png
    
    # import the necessary packages
    import numpy as np
    import argparse
    import cv2
    import csv
    
    # define a funtion of ROI calculating the average value in specified sample size
    def ROI(img,x,y,sample_size):
        Each_circle=img[y-sample_size:y+sample_size, x-sample_size:x+sample_size]
        average_values=np.mean(Each_circle)
        return average_values
    
    # open the csv file named circles_value
    circles_values=open('circles_value.csv', 'w')
    
    # construct the argument parser and parse the arguments
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--image", required = True, help = "Path to the image")
    args = vars(ap.parse_args())
    
    # load the image, clone it for output, and then convert it to grayscale
    image = cv2.imread(args["image"])
    output = image.copy()
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    # detect circles in the image
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2,50, 100, 1, 1, 20, 30)
    
    # 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")
    
    
    number=1
    font = cv2.FONT_HERSHEY_SIMPLEX
    
    # 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
        number=str(number)
        cv2.circle(output, (x, y), r, (0, 255, 0), 4)
        cv2.rectangle(output, (x - 10, y - 10), (x + 10, y + 10), (0, 128, 255), -1)
        # number each circle, but its result shows irregular pattern 
        cv2.putText(output, number, (x,y), font,0.5,(0,0,0),2,cv2.LINE_AA)
        # get the average value in specified sample size (20 x 20)
        sample_average_value=ROI(output, x, y, 20)
        # write the csv file with number, (x,y), and average pixel value
        circles_values.write(number+','+str(x)+','+str(y)+','+str(sample_average_value)+'\n')
        number=int(number)
        number+=1
    
    # show the output image
    cv2.namedWindow("image", cv2.WINDOW_NORMAL)
    cv2.imshow("image", output)
    cv2.waitKey(0)
    
    # close the csv file
    circles_values.close()
    

2 个答案:

答案 0 :(得分:1)

您的代码中的错误是您的号码取决于listcv2.HoughCircles返回的圈子的顺序,这可能是随机的,所以我在这种情况下要做的就是设计一个将每个圆的center(x, y)值转换为ID的公式,同一个圆将产生相同的ID,因为其中心位置保持不变:

def get_id_from_center(x, y):
    return x + y*50
for (x, y, r) in circles:
    number = str(get_id_from_center(x, y))

答案 1 :(得分:1)

您可以根据他们的x, y值,图片的宽度和粗线高度对您的圈子进行排序,例如:

import numpy as np
import argparse
import cv2
import csv

# define a funtion of ROI calculating the average value in specified sample size
def ROI(img,x,y,sample_size):
    Each_circle=img[y-sample_size:y+sample_size, x-sample_size:x+sample_size]
    average_values=np.mean(Each_circle)
    return average_values

# open the csv file named circles_value

with open('circles_value.csv', 'wb') as circles_values:
    csv_output = csv.writer(circles_values)

    # construct the argument parser and parse the arguments
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--image", required = True, help = "Path to the image")
    args = vars(ap.parse_args())

    # load the image, clone it for output, and then convert it to grayscale
    image = cv2.imread(args["image"])
    output = image.copy()
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # detect circles in the image
    circles = cv2.HoughCircles(gray, cv2.cv.CV_HOUGH_GRADIENT, 1.2,50, 100, 1, 1, 20, 30)

    # 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")

    font = cv2.FONT_HERSHEY_SIMPLEX
    height =  40

    # loop over the (x, y) coordinates and radius of the circles
    for number, (x, y, r) in enumerate(sorted(circles, key=lambda v: v[0] + (v[1] / height) * image.shape[1]), start=1):
        text = str(number)
        (tw, th), bl = cv2.getTextSize(text, font, 0.5, 2)      # So the text can be centred in the circle
        tw /= 2
        th = th / 2 + 2

        # 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), 3)
        cv2.rectangle(output, (x - tw, y - th), (x + tw, y + th), (0, 128, 255), -1)
        # number each circle, centred in the rectangle
        cv2.putText(output, text, (x-tw, y + bl), font, 0.5, (0,0,0), 2, cv2.CV_AA)
        # get the average value in specified sample size (20 x 20)
        sample_average_value = ROI(output, x, y, 20)
        # write the csv file with number, (x,y), and average pixel value
        csv_output.writerow([number, x, y, sample_average_value])

    # show the output image
    cv2.namedWindow("image", cv2.WINDOW_NORMAL)
    cv2.imshow("image", output)
    cv2.waitKey(0)

此外,使用Python的CSV库更容易将条目写入输出文件。这样,您无需将每个条目转换为字符串,并在每个条目之间添加逗号。 enumerate()可用于自动计算每个圈子。此外,getTextSize()可用于确定要打印的文本的尺寸,使您可以将其居中放置在矩形中。

这将为您提供如下输出:

Numbered circles

以CSV开头:

1,2,29,nan
2,51,19,nan
3,107,22,100.72437499999999
4,173,23,102.33291666666666
5,233,26,88.244791666666671
6,295,22,92.953541666666666
7,358,28,142.51625000000001
8,418,26,155.12875
9,484,31,127.02541666666667
10,547,25,112.57958333333333