I want to detect shapes like triangles, circles and rectangles in binary image after color segmentation but sometimes shapes are very ripped and jugged like in this picture. Is there any way to get a better shape?
Maybe that is something wrong with my color masks.
def redColorDetection(self, img):
self.low_red = np.array([160, 50, 5])
self.high_red = np.array([180, 255, 255])
red_mask = cv2.inRange(self.hsv, self.low_red, self.high_red)
return red_mask
CodePudding user response:
Red color is split in the cicular region of the HSV color space, so there is red part in 0 x and a red part in 360-x (180-x/2 in opencv because the 360° are divided by 2 there to fit into 8 bit).
For example 0 15 and 180-15 ( /-10 is also ok) in opencv give good results in your example:
int main()
{
cv::Mat img = cv::imread("C:/data/StackOverflow/redSign.jpg");
cv::Mat hsv;
cv::cvtColor(img, hsv, cv::COLOR_BGR2HSV);
cv::Scalar low_red1(165, 50, 5);
cv::Scalar high_red1(180, 255, 255);
cv::Scalar low_red2(0, 50, 5);
cv::Scalar high_red2(15, 255, 255);
cv::Mat mask1;
cv::Mat mask2;
cv::inRange(hsv, low_red1, high_red1, mask1);
cv::inRange(hsv, low_red2, high_red2, mask2);
cv::imshow("mask1", mask1);
cv::imshow("mask2", mask2);
cv::imshow("mask1 mask2", mask1 mask2);
cv::waitKey(0);
}
Giving this result:
If you want to segment red with a single inRange call you can shift the hue channel, but that's likely not more efficient, but might make it easier to write some kind of color segmentation general code: Have a look at the "shiftedH" part of:
import cv2
import numpy as np
# load image
img = cv2.imread('sign.jpg')
# convert to LAB
lab = cv2.cvtColor(img,cv2.COLOR_BGR2LAB)
# extract A channel
# The A axis is relative to the green–red opponent colors
# See https://en.wikipedia.org/wiki/CIELAB_color_space
A = lab[:,:,1]
# threshold A channel (choose one or the other depending upon what result you want)
thresh1 = cv2.threshold(A, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU)[1]
thresh2 = cv2.threshold(A, 150, 255, cv2.THRESH_BINARY)[1]
# save results
cv2.imwrite('sign_A_channel_lab.jpg', A)
cv2.imwrite('sign_threshold1.jpg', thresh1)
cv2.imwrite('sign_threshold2.jpg', thresh2)
# show results
cv2.imshow('A',A)
cv2.imshow('thresh1', thresh1)
cv2.imshow('thresh2', thresh2)
cv2.waitKey(0)
cv2.destroyAllWindows()
A channel from LAB:
Otsu Threshold:
Alternate Simple Threshold: