假设如果我们正在处理图像,有没有办法访问轮廓内的像素?
我已经使用函数 findContours() 找到了轮廓,甚至找到了时刻,但我找不到轮廓内的像素。
欢迎任何建议!
谢谢!
假设如果我们正在处理图像,有没有办法访问轮廓内的像素?
我已经使用函数 findContours() 找到了轮廓,甚至找到了时刻,但我找不到轮廓内的像素。
欢迎任何建议!
谢谢!
正如@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;
}
其次,您可以使用 Floodfill 执行您自己的标签。因此,您遍历图像并开始对每个白色像素进行填充,遍历边界矩形并获取具有相同种子颜色的所有点。这是代码:
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++;
}
}
}
我使用了这张图片:
以下是用于可视化的边界框和轮廓内的点:
使用 fillPoly 创建具有填充轮廓的新图像。
fillPoly(filledImage, contours, Scalar(255, 255, 255));
然后使用 findNonZero 找到该图像中的非零像素。
vector<Point> indices;
findNonZero(filledImage, indices);
“索引”结果是指轮廓内的像素
在轮廓轮廓的边界框内的所有像素上使用 pointPolygonTest http://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=pointpolygontest#pointpolygontest 。