假设我们正在处理图像,有没有办法访问轮廓内的像素?
我已经使用函数findContours()找到了轮廓,甚至找到了时刻,但我找不到轮廓内的像素。
任何建议都欢迎!!
谢谢!
答案 0 :(得分:5)
正如@Miki已经提到的,您可以使用connectedComponents来执行标记。然后你像@Amitay Nachmani建议的那样遍历对象的边界框。但是,您可以检查当前位置的值是否与当前标签匹配,而不是使用pointPolygonTest。这是一个小例子:
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <vector>
using namespace cv;
using namespace std;
Mat binary, labels, stats, centroids;
int main()
{
Mat src = imread("C:\\Users\\phili\\Pictures\\t06-4.png",0);
threshold(src, binary, 0, 255, CV_THRESH_OTSU);
int nLabels = connectedComponentsWithStats(binary, labels, stats, centroids);
vector<vector<Point>> blobs(nLabels-1);
for (int i = 1; i < nLabels; i++) //0 is background
{
//get bounding rect
int left = stats.at<int>(i, CC_STAT_LEFT) ;
int top = stats.at<int>(i, CC_STAT_TOP);
int width = stats.at<int>(i, CC_STAT_WIDTH);
int height = stats.at<int>(i, CC_STAT_HEIGHT);
blobs[i - 1].reserve(width*height);
int x_end = left + width;
int y_end = top + height;
for (int x = left; x < x_end; x++)
{
for (int y = top; y < y_end; y++)
{
Point p(x, y);
if (i == labels.at<int>(p))
{
blobs[i-1].push_back(p);
}
}
}
}
}
修改强>
由于您使用的是OpenCV 2.4,因此有两种方法可以实现相同的结果。 首先,您可以使用findContours来检测斑点,然后将它们(填充)绘制成具有特定颜色作为标签的新图像(请注意,您的斑点可能包含孔)然后在每个轮廓的边界矩形内迭代图像并获取带有当前轮廓标签的所有点。如果只是遍历二进制图像中的边界矩形,则会遇到与边界矩形重叠的对象的问题。 这是代码:
int getBlobs(Mat binary, vector<vector<Point>> & blobs)
{
Mat labels(src.size(), CV_32S);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
blobs.clear();
blobs.reserve(contours.size());
int count = 1; //0 is background
for (int i = 0; i < contours.size(); i++) // iterate through each contour.
{
//if contour[i] is not a hole
if (hierarchy[i][3] == -1)
{
//draw contour without holes
drawContours(labels, contours, i, Scalar(count),CV_FILLED, 0, hierarchy, 2, Point());
Rect rect = boundingRect(contours[i]);
int left = rect.x;
int top = rect.y;
int width = rect.width;
int height = rect.height;
int x_end = left + width;
int y_end = top + height;
vector<Point> blob;
blob.reserve(width*height);
for (size_t x = left; x < x_end; x++)
{
for (size_t y = top; y < y_end; y++)
{
Point p(x, y);
if (count == labels.at<int>(p))
{
blob.push_back(p);
}
}
}
blobs.push_back(blob);
count++;
}
}
count--;
return count;
}
其次,你可以用洪水填充你自己的工作。因此,您遍历图像并开始每个白色像素的填充,迭代边界矩形并获得具有相同seedColor的所有点。 这是代码:
int labeling(Mat binary, vector<vector<Point>> &blobs)
{
FindBlobs(binary, blobs);
return blobs.size();
}
与
void FindBlobs(const Mat &binary, vector<vector<Point>> &blobs)
{
blobs.clear();
// Fill the label_image with the blobs
// 0 - background
// 1 - unlabelled foreground
// 2+ - labelled foreground
cv::Mat label_image;
binary.convertTo(label_image, CV_32FC1);
float label_count = 2; // starts at 2 because 0,1 are used already
for (int y = 0; y < label_image.rows; y++) {
float *row = (float*)label_image.ptr(y);
for (int x = 0; x < label_image.cols; x++) {
if (row[x] != 255) {
continue;
}
cv::Rect rect;
cv::floodFill(label_image, Point(x, y), Scalar(label_count), &rect, Scalar(0), Scalar(0), 4 );
vector<Point> blob;
blob.reserve(rect.width*rect.height);
for (int i = rect.y; i < (rect.y + rect.height); i++) {
float *row2 = (float*)label_image.ptr(i);
for (int j = rect.x; j < (rect.x + rect.width); j++) {
if (row2[j] != label_count)
{
continue;
}
blob.push_back(Point(j, i));
}
}
blobs.push_back(blob);
label_count++;
}
}
}
我用过这张图片:
以下是边界框和轮廓内的点可视化:
答案 1 :(得分:0)
在轮廓轮廓的边界框内的所有像素上使用pointPolygonTest http://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=pointpolygontest#pointpolygontest。
答案 2 :(得分:0)
使用fillPoly创建带有填充轮廓的新图像。
fillPoly(filledImage, contours, Scalar(255, 255, 255));
然后使用findNonZero找到该图像中的非零像素。
vector<Point> indices;
findNonZero(filledImage, indices);
&#34;指数&#34;结果是指轮廓内的像素