Обнаружение формы в Python с использованием OpenCV

Я работаю над проектом, в котором я использую OpenCV для определения форм и их цветов.

Есть 5 цветов (красный, зеленый, желтый, синий и белый) и 4 формы (прямоугольник, звезда, круг и сердце). Я был в состоянии надежно различать цвета, и я могу определить формы, когда используемое изображение является нарисованным изображением, как это, используя этот код. Обратите внимание, что изображение только для демонстрации, значения диапазона в моем коде не для этих цветов.

import cv2
import numpy as np
class Shape():

    def __init__(self, color, shape, x, y, approx):
        self.color = color
        self.shape = shape
        self.x = x
        self.y = y
        self.approx = approx
def closing(mask):
kernel = np.ones((7,7),np.uint8) 
closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
return closing

def opening(mask):
    kernel = np.ones((6,6),np.uint8)
    opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
    return opening

#Define Red
lower_red = np.array([0, 90, 60], dtype=np.uint8)
upper_red = np.array([10, 255, 255], dtype=np.uint8)
red = [lower_red, upper_red, 'red']

#Define Green
lower_green = np.array([60, 55, 0], dtype=np.uint8)
upper_green = np.array([100, 255, 120], dtype=np.uint8)
green = [lower_green, upper_green, 'green']

#Define Blue
lower_blue = np.array([90, 20, 60], dtype=np.uint8)
upper_blue = np.array([130, 255, 180], dtype=np.uint8)
blue = [lower_blue, upper_blue, 'blue']

#Define Yellow
lower_yellow = np.array([5, 110, 200], dtype=np.uint8)
upper_yellow = np.array([50, 255, 255], dtype=np.uint8)
yellow = [lower_yellow, upper_yellow, 'yellow']

#Define White
lower_white = np.array([0, 90, 60], dtype=np.uint8)
upper_white = np.array([10, 255, 255], dtype=np.uint8)
white = [lower_white, upper_white ,'white']

colors = [red, green, blue, yellow, white]

def detect_shapes(image_location):
    #Open image
    img = cv2.imread(image_location)

    #Convert to hsv
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    #Shape list
    shapes = []

    #Lay over masks and detect shapes
    for color in colors:
        mask = cv2.inRange(hsv, color[0], color[1])
        mask = closing(mask)
        mask = opening(mask)
        contours, h = cv2.findContours(mask, 1, cv2.CHAIN_APPROX_SIMPLE)
        contours.sort(key = len)
        for contour in contours[-3:]:
            #Amount of edges
            approx = cv2.approxPolyDP(contour, 0.01*cv2.arcLength(contour, True), True)
            #Center locations
            M = cv2.moments(contour)
            if M['m00'] == 0.0:
                continue
            centroid_x = int(M['m10']/M['m00'])
            centroid_y = int(M['m01']/M['m00'])

            if len(approx) == 4:
                shape_name = 'rectangle'
            elif len(approx) == 10:
                shape_name = 'star'
            elif len(approx) >= 11:
                shape_name = 'oval'
            else:
                shape_name ='undefined'

            shape = Shape(color[2], shape_name, centroid_x, centroid_y, len(approx))
            shapes.append(shape)

    return shapes

Это в значительной степени основано на ответах на этот вопрос.

Однако, когда я пытаюсь определить формы на реальной фотографии, я не могу надежно использовать это. Количество краев, которые я получаю, сильно разнится. Это пример фотографии, на которой мне нужно распознать фигуры. Я предполагаю, что это происходит из-за небольших дефектов на краях фигур, но я не могу понять, как бы я приблизил эти края прямыми линиями или как бы я мог надежно распознать круги. Что мне нужно изменить в коде, чтобы сделать это? Интенсивный поиск в Google еще не дал мне ответа, но это может быть потому, что я не использую правильную терминологию в поисках...

Кроме того, если этот вопрос не отформатирован правильно, дайте мне знать!

1 ответ

Решение

Вот код я перехожу с вашего изображения, код сделаю

  1. Размытие источника
  2. Обнаружение Canny Edge.
  3. Найти контур.
  4. приблизительно PolyDP для контура.
  5. Проверьте общий размер точек окПолиДП.

Код:

   Mat src=imread("src.jpg",1);
   Mat thr,gray;
   blur(src,src,Size(3,3));
   cvtColor(src,gray,CV_BGR2GRAY);
   Canny(gray,thr,50, 190, 3, false );
   vector<vector<Point> > contours;
   vector<Vec4i> hierarchy;
   findContours( thr.clone(),contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0));

   vector<vector<Point> > contours_poly(contours.size());
   vector<Rect> boundRect( contours.size() );
   vector<Point2f>center( contours.size() );
   vector<float>radius( contours.size() );
   vector<vector<Point> >hull( contours.size() );
   for( int i = 0; i < contours.size(); i++ )
    {
    approxPolyDP( Mat(contours[i]), contours_poly[i], 10, true );
    boundRect[i] = boundingRect( Mat(contours_poly[i]) );
    minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] );
    convexHull( Mat(contours[i]), hull[i], false );

    if( contours_poly[i].size()>15) // Check for corner
       drawContours( src, contours_poly, i, Scalar(0,255,0), 2, 8, vector<Vec4i>(), 0, Point() ); // True object
    else
       drawContours( src, contours_poly, i, Scalar(0,0,255), 2, 8, vector<Vec4i>(), 0, Point() ); // false object
      //drawContours( src, hull, i, Scalar(0,0,255), 2, 8, vector<Vec4i>(), 0, Point() );
      // rectangle( src, boundRect[i].tl(), boundRect[i].br(), Scalar(0,255,0), 2, 8, 0 );
       //circle( src, center[i], (int)radius[i], Scalar(0,0,255), 2, 8, 0 );
    }
   imshow("src",src);
   imshow("Canny",thr);
   waitKey();

Другие вопросы по тегам