我正在尝试计算仅红色轮廓的均值和标准偏差。我怀疑Vec3b的红色色调值的HSV像素存储在0-10和165-179之间。

这是我的代码:

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>
#include <cmath>


using namespace cv;
using namespace std;

int main(int argc, char** argv) {


// Mat Declarations
// Mat img = imread("white.jpg");
// Mat src = imread("Rainbro.png");
Mat src = imread("multi.jpg");
// Mat src = imread("DarkRed.png");
Mat Hist;
Mat HSV;
Mat Edges;
Mat Grey;

vector<vector<Vec3b>> hueMEAN;
vector<vector<Point>> contours;

// Variables
int edgeThreshold = 1;
int const max_lowThreshold = 100;
int ratio = 3;
int kernel_size = 3;
int lowThreshold = 0;

// Windows
namedWindow("img", WINDOW_NORMAL);
namedWindow("HSV", WINDOW_AUTOSIZE);
namedWindow("Edges", WINDOW_AUTOSIZE);
namedWindow("contours", WINDOW_AUTOSIZE);

// Color Transforms
cvtColor(src, HSV, CV_BGR2HSV);
cvtColor(src, Grey, CV_BGR2GRAY);
// Perform Hist Equalization to help equalize Red hues so they stand out for
// better Edge Detection

equalizeHist(Grey, Grey);


// Image Transforms
blur(Grey, Edges, Size(3, 3));
Canny(Edges, Edges, max_lowThreshold, lowThreshold * ratio, kernel_size);
findContours(Edges, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

//Rainbro MAT
//Mat drawing = Mat::zeros(432, 700, CV_8UC1);

//Multi MAT
Mat drawing = Mat::zeros(630, 1200, CV_8UC1);

//Red variation Mat
//Mat drawing = Mat::zeros(600, 900, CV_8UC1);

vector <vector<Point>> ContourPoints;

/* This code for loops through all contours and assigns the value of the y coordinate as a parameter
for the row pointer in the HSV mat. The value vec3b pointer pointing to the pixel in the mat is accessed
and stored for any Hue value that is between 0-10 and 165-179 as Red only contours.*/

for (int i = 0; i < contours.size(); i++) {
    vector<Vec3b> vf;
    vector<Point> points;
    bool isContourRed = false;

    for (int j = 0; j < contours[i].size(); j++) {
        //Row Y-Coordinate of Mat from Y-Coordinate of Contour
        int MatRow = int(contours[i][j].y);
        //Row X-Coordinate of Mat from X-Coordinate of Contour
        int MatCol = int(contours[i][j].x);

        Vec3b *HsvRow = HSV.ptr <Vec3b>(MatRow);

        int h = int(HsvRow[int(MatCol)][0]);
        int s = int(HsvRow[int(MatCol)][1]);
        int v = int(HsvRow[int(MatCol)][2]);

        cout << "Coordinate: ";
        cout << contours[i][j].x;
        cout << ",";
        cout << contours[i][j].y << endl;
        cout << "Hue: " << h << endl;

        // Get contours that are only in the red spectrum Hue 0-10, 165-179
        if ((h <= 10 || h >= 165 && h <= 180) && ((s > 0) && (v > 0))) {
            cout << "Coordinate: ";
            cout << contours[i][j].x;
            cout << ",";
            cout << contours[i][j].y << endl;
            cout << "Hue: " << h << endl;

            vf.push_back(Vec3b(h, s, v));
            points.push_back(contours[i][j]);
            isContourRed = true;
        }

    }
    if (isContourRed == true) {
        hueMEAN.push_back(vf);
        ContourPoints.push_back(points);
    }
}

drawContours(drawing, ContourPoints, -1, Scalar(255, 255, 255), 2, 8);

// Calculate Mean and STD for each Contour
cout << "contour Means & STD of Vec3b:" << endl;
for (int i = 0; i < hueMEAN.size(); i++) {

    Scalar meanTemp = mean(hueMEAN.at(i));
    Scalar sdTemp;
    cout << i << ": " << endl;
    cout << meanTemp << endl;
    cout << " " << endl;
    meanStdDev(hueMEAN.at(i), meanTemp, sdTemp);
    cout << sdTemp << endl;
    cout << " " << endl;
}
cout << "Actual Contours: " << contours.size() << endl;
cout << "# Contours: " << hueMEAN.size() << endl;

imshow("img", src);
imshow("HSV", HSV);
imshow("Edges", Edges);
imshow("contours", drawing);
waitKey(0);

return 0;
}

在这种情况下,我遇到了一个问题:c&#43;&#43; - 仅对具有HSV范围的像素的红色轮廓进行过滤-LMLPHP

原始图像在右侧,左侧显示HSV垫,边缘检测,并且箭头指向在过滤后绘制的轮廓垫。

这是源图像:c&#43;&#43; - 仅对具有HSV范围的像素的红色轮廓进行过滤-LMLPHP

过滤完成后,我只需计算均值和STD。

我感觉我的范围不适用于0-10和165-179。任何建议或进一步的改进都会有很大帮助。

谢谢。

最佳答案

快速测试显示该范围正确。没有所有轮廓提取内容,如果我仅使用0-10和165-179范围过滤颜色,则会在输入图像的中下部获得两个红色框。

您看到的轮廓伪影实际上可能来自JPEG伪影(如果放大到白色和红色框之间的极限,则由于JPEG压缩,您会发现它是渐进而不锐利的)和事实您仅在色相通道中达到阈值。在低饱和度下,您不希望使用的许多灰色颜色实际上会适合您的色相阈值。解决方案是同时过滤S和V通道中的像素值。

在您的代码中,这意味着将if ((h <= 10 || h >= 165 && h <= 180) && ((s > 0) && (v > 0))) {行更改为if ((h <= 10 || h >= 165 && h <= 180) && ((s > 50) && (v > 50))) {
值50在该特定样本图像上起作用,但是正确的值当然取决于您的输入图像。

关于c++ - 仅对具有HSV范围的像素的红色轮廓进行过滤,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46969487/

10-12 00:30
查看更多