繁体   English   中英

如何在OpenCV中计算颜色段中的像素

[英]How to count pixels in color segment in OpenCV

我有一个OpenCV C ++应用程序。 我已经用pyrMeanShiftFiltering函数对图像进行了分割。 现在,我需要计算一个段中的像素和同一段中具有最频繁值的像素数,以便计算它们之间的比率。 我该怎么办?

我正在使用筑波图像,代码是。
筑波

Mat image, segmented;
image = imread("TsukubaL.jpg", 1 );
pyrMeanShiftFiltering(image, segmented, 16, 32);

分割后的图像为:
分段筑波
如果考虑单个段中的像素,则我对该段中的像素进行计数的部分是:

int cont=0;
Vec3b x = segmented.at<Vec3b>(160, 136);
for(int i = 160; i < segmented.rows; ++i) { //check right-down
    for(int j = 136; j < segmented.cols; ++j) {
        if(segmented.at<Vec3b>(i, j) == x)
            cont++;
        else
            continue;
    }
}
for(int i = 160; i > 0; --i) {  //check right-up
    for(int j = 136; j < segmented.cols; ++j) {
        if(segmented.at<Vec3b>(i, j) == x)
            cont++;
        else
            continue;
    }
}
for(int i = 160; i < segmented.rows; ++i) { //check down-left
    for(int j = 136; j > 0; --j) {
        if(segmented.at<Vec3b>(i, j) == x)
            cont++;
        else
            continue;
    }
}
for(int i = 160; i > 0; --i) {  //check up-left
    for(int j = 136; j > 0; --j) {
        if(segmented.at<Vec3b>(i, j) == x)
            cont++;
        else
            continue;
    }
}
cout<<"Pixel "<<x<<"cont = "<<cont<<endl;  

在此示例中,我考虑位置(160,136)处的白色像素,并从该像素开始在四个方向上将相同像素计数到中心像素,输出为:

像素[206,222,240] cont = 127

这可能是一个好的方法吗?

首先,您需要定义一个具有与初始点相同颜色(此处称为种子 )的像素的蒙版。 您可以使用给定公差的inRange 假设种子在头上 ,您将得到类似以下内容的东西:

在此处输入图片说明

现在,您需要找到包含种子的已连接组件。 您可以通过多种方式执行此操作。 在这里,我修改了生成标记算法(可以在此处找到)。 您将获得包含种子的斑点的点列表。 然后可以使用以下几点制作蒙版:

在此处输入图片说明

现在您已经拥有了所有点,现在可以轻松地找到线段中的点数。 要查找最常见的颜色,可以使用该段中包含的BGR值制作直方图。 由于具有所有RGB值的直方图将具有256 * 256 * 256个bin,因此使用地图更为实用。 我修改了此处找到的代码以使用给定的蒙版制作直方图。

现在,您只需要查找频率较高的颜色值即可。 对于此示例,我得到了:

# points in segment: 2860
Most frequent color: [209, 226, 244]    #: 168

看一下代码:

#include <opencv2/opencv.hpp>
#include <vector>
#include <stack>
#include <map>
using namespace cv;
using namespace std;

vector<Point> connected_components(const Mat1b& img, Point seed)
{
    Mat1b src = img > 0;

    int label = 0;
    int w = src.cols;
    int h = src.rows;
    int i;

    cv::Point point;

    // Start from seed
    std::stack<int, std::vector<int>> stack2;
    i = seed.x + seed.y*w;
    stack2.push(i);

    // Current component
    std::vector<cv::Point> comp;

    while (!stack2.empty())
    {
        i = stack2.top();
        stack2.pop();

        int x2 = i%w;
        int y2 = i / w;

        src(y2, x2) = 0;

        point.x = x2;
        point.y = y2;
        comp.push_back(point);

        // 4 connected
        if (x2 > 0 && (src(y2, x2 - 1) != 0))
        {
            stack2.push(i - 1);
            src(y2, x2 - 1) = 0;
        }
        if (y2 > 0 && (src(y2 - 1, x2) != 0))
        {
            stack2.push(i - w);
            src(y2 - 1, x2) = 0;
        }
        if (y2 < h - 1 && (src(y2 + 1, x2) != 0))
        {
            stack2.push(i + w);
            src(y2 + 1, x2) = 0;
        }
        if (x2 < w - 1 && (src(y2, x2 + 1) != 0))
        {
            stack2.push(i + 1);
            src(y2, x2 + 1) = 0;
        }

        // 8 connected
        if (x2 > 0 && y2 > 0 && (src(y2 - 1, x2 - 1) != 0))
        {
            stack2.push(i - w - 1);
            src(y2 - 1, x2 - 1) = 0;
        }
        if (x2 > 0 && y2 < h - 1 && (src(y2 + 1, x2 - 1) != 0))
        {
            stack2.push(i + w - 1);
            src(y2 + 1, x2 - 1) = 0;
        }
        if (x2 < w - 1 && y2>0 && (src(y2 - 1, x2 + 1) != 0))
        {
            stack2.push(i - w + 1);
            src(y2 - 1, x2 + 1) = 0;
        }
        if (x2 < w - 1 && y2 < h - 1 && (src(y2 + 1, x2 + 1) != 0))
        {
            stack2.push(i + w + 1);
            src(y2 + 1, x2 + 1) = 0;
        }
    }

    return comp;
}


struct lessVec3b
{
    bool operator()(const Vec3b& lhs, const Vec3b& rhs) {
        return (lhs[0] != rhs[0]) ? (lhs[0] < rhs[0]) : ((lhs[1] != rhs[1]) ? (lhs[1] < rhs[1]) : (lhs[2] < rhs[2]));
    }
};

map<Vec3b, int, lessVec3b> getPalette(const Mat3b& src, const Mat1b& mask)
{
    map<Vec3b, int, lessVec3b> palette;
    for (int r = 0; r < src.rows; ++r)
    {
        for (int c = 0; c < src.cols; ++c)
        {
            if (mask(r, c))
            {
                Vec3b color = src(r, c);
                if (palette.count(color) == 0)
                {
                    palette[color] = 1;
                }
                else
                {
                    palette[color] = palette[color] + 1;
                }
            }
        }
    }
    return palette;
}


int main()
{
    // Read the image
    Mat3b image = imread("tsukuba.jpg");

    // Segment
    Mat3b segmented;
    pyrMeanShiftFiltering(image, segmented, 16, 32);

    // Seed
    Point seed(140, 160);

    // Define a tolerance
    Vec3b tol(10,10,10);

    // Extract mask of pixels with same value as seed
    Mat1b mask;
    inRange(segmented, segmented(seed) - tol, segmented(seed) + tol, mask);

    // Find the connected component containing the seed
    vector<Point> pts = connected_components(mask, seed);

    // Number of pixels in the segment
    int n_of_pixels_in_segment = pts.size();

    Mat1b mask_segment(image.rows, image.cols, uchar(0));
    for (const auto& pt : pts)
    {
        mask_segment(pt) = uchar(255);
    }

    // Get palette
    map<Vec3b, int, lessVec3b> palette = getPalette(segmented, mask_segment);

    // Get most frequent color 
    Vec3b most_frequent_color;
    int freq = 0;

    for (const auto& pal : palette)
    {
        if (pal.second > freq)
        {
            most_frequent_color = pal.first;
            freq = pal.second;
        }
    }

    cout << "# points in segment: " << n_of_pixels_in_segment << endl;
    cout << "Most frequent color: " << most_frequent_color <<  " \t#: " << freq << endl;


    return 0;
}

在按照上一个答案所示或通过任何其他方式创建所需的蒙版之后,可以在蒙版图像周围创建轮廓。 这将使您可以使用轮廓轮廓函数直接计算段内的像素数。

您可以将所选区域划分为一个新的子垫,并在该子垫上计算直方图以获得最频繁的值。 如果仅关注颜色值而不关注亮度值,则还应根据要求将图像转换为HSV,LAB或YCbCr颜色空间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM