I am working on a small OpenCV project to detect lines of a certain colour from a mobile phone camera.
In short would like to:
Those are the functions that I'd like to use but not quiet sure how to fill the missing bits.
This is the processImage function called from an smartphone app when processing images from an instance of CvVideoCamera
- (void)processImage:(Mat&)image;
{
cv::Mat orig_image = image.clone();
cv::Mat red_image = ??
// Apply houghes transformation to detect lines between a minimum length and a maximum length (I was thinking of using the CV_HOUGH_PROBABILISTIC method..)
// Comment.. see below..
I am unable to understand the documentation here as the C++ method signature does not have a method field
vector<Vec2f> lines;
From the official documentation:
C++: void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
Taken from sample code, haven't understood properly how it works..
(e.g. what's the usage of theta? How does giving a different angle reflect into line detection?)
for( size_t i = 0; i < lines.size(); i++ )
{
Here I should only consider lines above a certain size.. (no idea how)
}
Here I should then add the resulting lines to original image (no idea how) so that they can be shown on the screen..
Any help would be greatly appreciated.
You can use HSV color space to extract color tone information.
Here's some code with comments, if there are any questions feel free to ask:
int main(int argc, char* argv[])
{
cv::Mat input = cv::imread("C:/StackOverflow/Input/coloredLines.png");
// convert to HSV color space
cv::Mat hsvImage;
cv::cvtColor(input, hsvImage, CV_BGR2HSV);
// split the channels
std::vector<cv::Mat> hsvChannels;
cv::split(hsvImage, hsvChannels);
// hue channels tells you the color tone, if saturation and value aren't too low.
// red color is a special case, because the hue space is circular and red is exactly at the beginning/end of the circle.
// in literature, hue space goes from 0 to 360 degrees, but OpenCV rescales the range to 0 up to 180, because 360 does not fit in a single byte. Alternatively there is another mode where 0..360 is rescaled to 0..255 but this isn't as common.
int hueValue = 0; // red color
int hueRange = 15; // how much difference from the desired color we want to include to the result If you increase this value, for example a red color would detect some orange values, too.
int minSaturation = 50; // I'm not sure which value is good here...
int minValue = 50; // not sure whether 50 is a good min value here...
cv::Mat hueImage = hsvChannels[0]; // [hue, saturation, value]
// is the color within the lower hue range?
cv::Mat hueMask;
cv::inRange(hueImage, hueValue - hueRange, hueValue + hueRange, hueMask);
// if the desired color is near the border of the hue space, check the other side too:
// TODO: this won't work if "hueValue + hueRange > 180" - maybe use two different if-cases instead... with int lowerHueValue = hueValue - 180
if (hueValue - hueRange < 0 || hueValue + hueRange > 180)
{
cv::Mat hueMaskUpper;
int upperHueValue = hueValue + 180; // in reality this would be + 360 instead
cv::inRange(hueImage, upperHueValue - hueRange, upperHueValue + hueRange, hueMaskUpper);
// add this mask to the other one
hueMask = hueMask | hueMaskUpper;
}
// now we have to filter out all the pixels where saturation and value do not fit the limits:
cv::Mat saturationMask = hsvChannels[1] > minSaturation;
cv::Mat valueMask = hsvChannels[2] > minValue;
hueMask = (hueMask & saturationMask) & valueMask;
cv::imshow("desired color", hueMask);
// now perform the line detection
std::vector<cv::Vec4i> lines;
cv::HoughLinesP(hueMask, lines, 1, CV_PI / 360, 50, 50, 10);
// draw the result as big green lines:
for (unsigned int i = 0; i < lines.size(); ++i)
{
cv::line(input, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(0, 255, 0), 5);
}
cv::imwrite("C:/StackOverflow/Output/coloredLines_mask.png", hueMask);
cv::imwrite("C:/StackOverflow/Output/coloredLines_detection.png", input);
cv::imshow("input", input);
cv::waitKey(0);
return 0;
}
using this input image:
Will extract this "red" color (adjust hueValue
and hueRange
to detect different colors):
and HoughLinesP detects those lines from the mask (should work with HoughLines
similarly):
Here's another set of images with non-lines too...
About your different questions:
There are two functions HoughLines and HoughLinesP. HoughLines does not extract a line length, but you can compute it in a post-processing by checking again, which pixels of the edge-mask (HoughLines input) correspond to the extracted line.
parameters:
image - edge image (should be clear?)
lines - lines given by angle and position, no length or sth. they are interpreted infinitely long
rho - the accumulator resolution. The bigger, the more robust in case of slightly distorted lines it should be, but the less accurate in the extracted lines' position/angle
threshold - the bigger the less false positives, but you might miss some lines
theta - angle resolution: the smaller, the more different lines (depending on the orientation) can be detected. If your line's orientation does not fit in the angle steps, the line might not be detected. For example if you CV_PI/180
will detect in 1°
resolution, if your line has a 0.5°
(e.g. 33.5°
) orientation, it might be missed.
I'm not so extremely sure about all the parameters, maybe you'll have to look at the literature about hough line detection, or someone else can add some hints here.
If you instead use cv::HoughLinesP
, line segments with start- and end-point will be detected, which is easier to interpret and you can compute the line length from cv::norm(cv::Point(lines[i][0], lines[i][1]) - cv::Point(lines[i][2], lines[i][3]))