OpenCV基础优化之使用drawContours
本文由 @lonelyrains出品,转载请注明出处。
文章链接: http://blog.csdn.net/lonelyrains/article/details/50215549
最近要使用一个基于点组成的轮廓的过滤效果。即轮廓内的点全部保留,外部的点全部变黑。
一开始想到的做法是按顺时针顺序输入轮廓点,然后将frame内所有的点都按照对所有边的顺时针法则判断是否保留。例如如下代码中,取一点pTemp,如果pTemp->p0->p1是顺时针,则可能保留pTemp,否则“拉黑”;直到每个点对所有的轮廓边都做同样的操作,才决定该点是拉黑还是保留。
虽然加了openmp优化,但是效果并不好。
// 区域外的部分全部置为0 // vector p 顺序为顺时针
int filterArea(cv::Mat &frame, vector<cv::Point> &p)
{
//if(p.size() == 4)
{
/* 四点的顺序是:
p0 ----- p1
| |
| |
| |
p3 ----- p2
*/
int nc = frame.channels();
#pragma omp parallel for
for (int j = 0; j < frame.rows; j++)
{
uchar* data = frame.ptr<uchar>(j);
for (int i = 0; i < frame.cols*nc; i += nc)
{
// 可能不是一个正矩形,不能简单的判断x/y,而是应该判断是否在直线一侧
// if(i/nc < p[0].x || j < p[0].y || i/nc > p[3].x || j > p[3].y)
bool bfilterPoint = false;
for (int k = p.size() - 1; k >= 0; k--)
{
if (k != 0)
{
if (isClockwise(cv::Point(i / nc, j), p[k], p[k - 1]) == false)
{
bfilterPoint = true;
}
}
else
{
if (isClockwise(cv::Point(i / nc, j), p[k], p[p.size() - 1]) == false)
{
bfilterPoint = true;
}
}
}
if (bfilterPoint == true)
{
for (int k = 0; k < nc; k++)
{
data[i / nc*nc + k] = 0;
}
}
}
}
}
return 0;
}
优化之后的做法非常简单,直接轮廓填充出一个mask,然后按位与原矩阵
// 区域外的部分全部置为0 // vector p 顺序为顺时针
int filterArea(cv::Mat &frame, vector<cv::Point> &p)
{
cv::Mat mask = cv::Mat::zeros(frame.size(), frame.type());
imshow("mask1", mask);
vector< vector<cv::Point> > contours;
vector<cv::Point>contour;
for (int i = 0; i < p.size(); i++)
{
contour.push_back(p[i]);
}
contour.push_back(p[0]);
contours.push_back(contour);
for (int i = 0; i < contours.size(); i++)
{
cv::drawContours(mask, contours, i, cv::Scalar(255, 255, 255), CV_FILLED, 8);
}
imshow("mask", mask);
frame = frame & mask;
mask.release();
return 0;
}
代码又少,逻辑又清晰,输入要求又简单,不需要按顺序,而且使用效率很高。