2016-04-03 148 views
1

不能單獨的對象我有3個辣椒這一形象:在C++ OpenCV的HSV圖像分離

我需要這個圖片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); 
    } 

} 
+0

[GIMP的最大RGB](http://docs.gimp.org/en/plug-in-max-rgb。HTML)似乎值得去嘗試 – sturkmen

回答

4

作爲第一步,讓我們減少使用k-means clustering圖像中的顏色數量。

接下來,讓我們將圖像轉換到HSV空間,並把它分割成單獨的色調,飽和度和值部件。

色調:

色相(colourmapped):

飽和度:

值:

的色調分量是足夠的算法的其餘部分。 我們通過選擇適合三種顏色的範圍內的像素來創建三個蒙版。

紅:

黃色:

綠色:

我們清理使用形態轉換的掩模圖像(侵蝕,擴張)。接下來,我們檢測輪廓並只選擇面積大於某個閾值的那些(我選擇了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); 
} 
+0

幹得好。您可以簡化kmeans代碼[一點點](http://stackoverflow.com/a/34734939/5008845); D – Miki

+0

@Miki謝謝,我更新了代碼。 –