c++ - 无法在 C++ OpenCV HSV 图像分离中分离对象

标签 c++ opencv filter

我有这张图片和 3 个辣椒:

我需要将这张图片转换为 HSV 格式,然后将每个辣椒分成自己的图像。

到目前为止,我似乎能够很好地将红辣椒与其他辣椒区分开来。但是,我似乎无法弄清楚如何分离其他辣椒。

这是我的代码:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <cmath>
#include <string>
#include <vector>

int main(int argc, char *argv[]){
    cv::Mat im_in;
    cv::Mat hsv_in;
    cv::Mat bgr_in;
    cv::Mat orig_in;
    cv::Mat im_o1;
    cv::Mat im_o2;
    cv::Mat im_o3;
    // Read image
    if (argc<2){
    im_in = cv::imread("colorpeppers.jpg");
    }
    if (argc==2){
        im_in=cv::imread((argv[1]));
    }
    if (argc>2){
        std::cout<<"Error! Too many arguments!"<<std::endl;
    }
    if (im_in.empty()){
        std::cout << "error detected. something went wrong with opening the image. is it empty? exiting"<<std::endl;
        return -1;
    }
    cv::Mat orig_image = im_in.clone();
    cv::medianBlur(im_in, im_in, 3);

    cv::cvtColor(im_in, hsv_in, cv::COLOR_BGR2HSV);
    cv::namedWindow("Original Image", cv::WINDOW_AUTOSIZE);
    cv::imshow("Orginal Image", im_in);

    cv::namedWindow("Orginal Image converted to HSV", cv::WINDOW_AUTOSIZE);
    cv::imshow("Original Image converted to HSV", hsv_in);
    cv::Mat lower_red_hue_range;
    cv::Mat upper_red_hue_range;
    cv::Mat lower_green_hue_range;
    cv::Mat upper_green_hue_range;
    cv::Mat lower_yellow_hue_range;
    cv::Mat upper_yellow_hue_range;


    cv::inRange(hsv_in, cv::Scalar(0,100,100), cv::Scalar(10,255,255), lower_red_hue_range);
    cv::inRange(hsv_in, cv::Scalar(160,100,100),cv::Scalar(179, 255, 255), upper_red_hue_range);
    cv::inRange(hsv_in, cv::Scalar(0,100,100), cv::Scalar(10,255,255), lower_green_hue_range);
    cv::inRange(hsv_in, cv::Scalar(50,100,100),cv::Scalar(70,255,255), upper_green_hue_range);
    cv::inRange(hsv_in, cv::Scalar(0,100,100),cv::Scalar(20,0,0),lower_yellow_hue_range);
    cv::inRange(hsv_in,cv::Scalar(10,100,100),cv::Scalar(50,110,110),upper_yellow_hue_range);

    //combining the above
    cv::Mat red_hue_image=im_in.clone();
    cv::Mat green_hue_image=im_in.clone();
    cv::Mat yellow_hue_image=im_in.clone();
    cv::addWeighted(lower_red_hue_range, 1.0, upper_red_hue_range, 1.0, 0.0, red_hue_image);
    cv::addWeighted(lower_green_hue_range, 1.0, upper_green_hue_range, 1.0, 0.0, green_hue_image);
    cv::addWeighted(lower_yellow_hue_range, 1.0, upper_yellow_hue_range, 1.0, 0.0, yellow_hue_image);
    cv::GaussianBlur(red_hue_image, red_hue_image, cv::Size(9,9), 2, 2);
    cv::GaussianBlur(green_hue_image, green_hue_image, cv::Size(9,9),2,2);
    cv::GaussianBlur(yellow_hue_image, yellow_hue_image, cv::Size(9,9),2,2);

    cv::namedWindow("Threshold lower red image", cv::WINDOW_AUTOSIZE);
    cv::imshow("Threshold lower red image", lower_red_hue_range);
    cv::namedWindow("Threshold upper red image", cv::WINDOW_AUTOSIZE);
    cv::imshow("Threshold upper red image", upper_red_hue_range);
    cv::namedWindow("Combined Threshold red Images", cv::WINDOW_AUTOSIZE);
    cv::imshow("Combined Threshold red Images", red_hue_image);

    cv::namedWindow("Threshold lower green image", cv::WINDOW_AUTOSIZE);
    cv::imshow("Threshold lower green image", lower_green_hue_range);
    cv::namedWindow("Threshold upper green image", cv::WINDOW_AUTOSIZE);
    cv::imshow("Threshold upper green image", upper_green_hue_range);
    cv::namedWindow("Combined Threshold green Images", cv::WINDOW_AUTOSIZE);
    cv::imshow("Combined Threshold green Images", green_hue_image);

    cv::namedWindow("Threshold lower yellow image", cv::WINDOW_AUTOSIZE);
    cv::imshow("Threshold lower yellow image", lower_yellow_hue_range);
    cv::namedWindow("Threshold upper yellow image", cv::WINDOW_AUTOSIZE);
    cv::imshow("Threshold upper yellow image", upper_yellow_hue_range);
    cv::namedWindow("Combined Threshold yellow Images", cv::WINDOW_AUTOSIZE);
    cv::imshow("Combined Threshold yellow Images", yellow_hue_image);



    //cv::Mat redpepper;//=red_hue_image.clone();
    //cv::Mat redpepper_hsv;
    //cvtColor(redpepper, redpepper_hsv,CV_BGR2HSV);
//    for(int i = 0; i < redpepper.rows;i++){
  //      for(int j = 0; j <redpepper.cols;j++){




    char k;
    for (int x=1;x<15;x++){
        k=cvWaitKey(0);
    }

}

最佳答案

第一步,让我们使用 k-means clustering 减少图像中的颜色数量.

接下来,让我们将图像转换为 HSV 空间并将其拆分为单独的色调、饱和度和明度分量。

色调:

色调(彩色映射):

饱和度:

值:

色调分量足以用于算法的其余部分。 我们通过在适合三种颜色的范围内选择像素来创建三个蒙版。

红色:

黄色:

绿色:

我们使用形态变换(侵 eclipse 、扩张)清理蒙版图像。接下来,我们检测轮廓并只选择面积大于某个阈值的轮廓(我选择了 5000 像素)。我们通过填充满足标准的轮廓来生成新的蒙版。

红色:

黄色:

绿色:

例如,现在我们可以绘制轮廓...

红色:

黄色:

绿色:

代码:

#include <opencv2/opencv.hpp>

#include <cstdint>
#include <iostream>
#include <vector>

cv::Mat cluster_image(cv::Mat const& img)
{
    int K = 4;
    int n = img.rows * img.cols;
    cv::Mat data = img.reshape(1, n);
    data.convertTo(data, CV_32F);

    std::vector<int> labels;
    cv::Mat1f colors;
    cv::kmeans(data, K, labels
        , cv::TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 10000, 0.0001)
        , 5, cv::KMEANS_PP_CENTERS, colors);

    for (int i = 0; i < n; ++i) {
        data.at<float>(i, 0) = colors(labels[i], 0);
        data.at<float>(i, 1) = colors(labels[i], 1);
        data.at<float>(i, 2) = colors(labels[i], 2);
    }

    cv::Mat reduced = data.reshape(3, img.rows);
    reduced.convertTo(reduced, CV_8U);

    return reduced;
}

cv::Mat filter_mask(cv::Mat& img, cv::Mat& mask)
{
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5));
    cv::Mat filtered;
    cv::erode(mask, filtered, kernel, cv::Point(-1, -1), 2);
    cv::dilate(filtered, filtered, kernel, cv::Point(-1, -1), 2);

    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;

    cv::findContours(filtered, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    cv::Mat output_mask = cv::Mat::zeros(mask.size(), CV_8UC1);

    double const MIN_CONTOUR_AREA(5000.0);
    for (int i(0); i < contours.size(); ++i) {
        double area = cv::contourArea(contours[i]);

        if (area >= MIN_CONTOUR_AREA) {
            cv::drawContours(output_mask, contours, i, cv::Scalar(255), CV_FILLED);
        }
    }

    cv::dilate(output_mask, output_mask, kernel, cv::Point(-1, -1), 1);

    return output_mask;
}

void highlight_mask(std::string const& filename, cv::Mat& img, cv::Mat& mask)
{
    cv::Mat output = img.clone();

    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
    cv::drawContours(output, contours, 0, cv::Scalar(255, 0, 0), 2);

    cv::imwrite(filename, output);
}


int main(int argc, char *argv[])
{
    cv::Mat orig_image(cv::imread("d:\\code\\shit\\so03\\bin\\runtime\\Debug\\peppers.png"));
    if (orig_image.empty()) {
        std::cerr << "Input image empty." << std::endl;
        return -1;
    }

    cv::Mat im_in;
    cv::medianBlur(orig_image, im_in, 3);

    cv::Mat clustered = cluster_image(im_in);
    cv::imwrite("peppers_clustered.png", clustered);

    cv::Mat hsv_in;
    cv::cvtColor(clustered, hsv_in, cv::COLOR_BGR2HSV);

    uint32_t HUE(0), SAT(1), VAL(2);
    std::vector<cv::Mat> h_s_v(3);
    cv::split(hsv_in, h_s_v);
    cv::imwrite("peppers_hue.png", h_s_v[HUE]);
    cv::imwrite("peppers_sat.png", h_s_v[SAT]);
    cv::imwrite("peppers_val.png", h_s_v[VAL]);



    cv::Mat red_mask_a;
    cv::inRange(h_s_v[HUE], cv::Scalar(2), cv::Scalar(10), red_mask_a);
    cv::Mat red_mask_b = filter_mask(im_in, red_mask_a);
    cv::imwrite("peppers_red_mask_a.png", red_mask_a);
    cv::imwrite("peppers_red_mask_b.png", red_mask_b);

    cv::Mat yellow_mask_a;
    cv::inRange(h_s_v[HUE], cv::Scalar(15), cv::Scalar(25), yellow_mask_a);
    cv::Mat yellow_mask_b = filter_mask(im_in, yellow_mask_a);
    cv::imwrite("peppers_yellow_mask_a.png", yellow_mask_a);
    cv::imwrite("peppers_yellow_mask_b.png", yellow_mask_b);

    cv::Mat green_mask_a;
    cv::inRange(h_s_v[HUE], cv::Scalar(40), cv::Scalar(50), green_mask_a);
    cv::Mat green_mask_b = filter_mask(im_in, green_mask_a);
    cv::imwrite("peppers_green_mask_a.png", green_mask_a);
    cv::imwrite("peppers_green_mask_b.png", green_mask_b);

    highlight_mask("peppers_red_out.png", orig_image, red_mask_b);
    highlight_mask("peppers_yellow_out.png", orig_image, yellow_mask_b);
    highlight_mask("peppers_green_out.png", orig_image, green_mask_b);
}

关于c++ - 无法在 C++ OpenCV HSV 图像分离中分离对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36390083/

相关文章:

c++ - 在 cpack 输出中包含外部库

python-2.7 - Python-OpenCV cv2 OpenCV错误: Assertion failed (scn == 3 || scn == 4) in unknown function,文件..\..\..\modules\imgproc\src\color.cpp

for-loop - 使用 filter() 的惯用方式

c++ - C++ Visual Studio 2008 中未声明的标识符

c++ - C++ 中的 inData.open 和 inData.close

c++ - Clang:从命令行或 Python 可靠地检测支持的 C++ 标准

python - 如何修复python中opencv中的错误 "QObject::moveToThread:"?

c++ - 链接到从源代码构建的 OpenCV 时出现 Cmake 问题

vba - 在过滤器中使用 "Or"

git 查找被 smudge/clean 过滤器过滤的文件的文件名