I have a picture like this:
And then I transform it into binary image and use canny to detect edge of the picture:
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY) edge = Image.fromarray(edges)
And then I get the result as:
I want to get the area of 2 like this:
My solution is to use HoughLines to find lines in the picture and calculate the area of triangle formed by lines. However, this way is not precise because the closed area is not a standard triangle. How to get the area of region 2?
The bottom contour is not complete, it is open from other 3 sides, you need to manually draw white lines around the border and then find the contour area.
Commented Apr 2, 2019 at 4:57A simple approach using floodFill and countNonZero could be the following code snippet. My standard quote on contourArea from the help:
The function computes a contour area. Similarly to moments , the area is computed using the Green formula. Thus, the returned area and the number of non-zero pixels, if you draw the contour using drawContours or fillPoly , can be different. Also, the function will most certainly give a wrong results for contours with self-intersections.
import cv2 import numpy as np # Input image img = cv2.imread('images/YMMEE.jpg', cv2.IMREAD_GRAYSCALE) # Needed due to JPG artifacts _, temp = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY) # Dilate to better detect contours temp = cv2.dilate(temp, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))) # Find largest contour cnts, _ = cv2.findContours(temp, cv2.RETR_EXTERNAL , cv2.CHAIN_APPROX_NONE) largestCnt = [] for cnt in cnts: if (len(cnt) > len(largestCnt)): largestCnt = cnt # Determine center of area of largest contour M = cv2.moments(largestCnt) x = int(M["m10"] / M["m00"]) y = int(M["m01"] / M["m00"]) # Initiale mask for flood filling width, height = temp.shape mask = img2 = np.ones((width + 2, height + 2), np.uint8) * 255 mask[1:width, 1:height] = 0 # Generate intermediate image, draw largest contour, flood filled temp = np.zeros(temp.shape, np.uint8) temp = cv2.drawContours(temp, largestCnt, -1, 255, cv2.FILLED) _, temp, mask, _ = cv2.floodFill(temp, mask, (x, y), 255) temp = cv2.morphologyEx(temp, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))) # Count pixels in desired region area = cv2.countNonZero(temp) # Put result on original image img = cv2.putText(img, str(area), (x, y), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, 255) cv2.imshow('Input', img) cv2.imshow('Temp image', temp) cv2.waitKey(0)
Caveat: findContours has some problems one the right side, where the line is very close to the bottom image border, resulting in possibly omitting some pixels.
Disclaimer: I'm new to Python in general, and specially to the Python API of OpenCV (C++ for the win). Comments, improvements, highlighting Python no-gos are highly welcome!