【问题标题】:Segmentation of foreground from background从背景中分割前景
【发布时间】:2016-03-16 19:51:09
【问题描述】:

我目前正在做一个使用拉卡坦香蕉的项目,我想知道如何进一步分离前景和背景:

我已经获得了仅使用腐蚀、膨胀和阈值处理的分段图像。问题是它仍然没有正确分割。

这是我的代码:

    cv::Mat imggray, imgthresh, fg, bgt, bg;
    cv::cvtColor(src, imggray, CV_BGR2GRAY); //Grayscaling the image from RGB color space
    cv::threshold(imggray, imgthresh, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); //Create an inverted binary image from the grayscaled image
    cv::erode(imgthresh, fg, cv::Mat(), cv::Point(-1, -1), 1); //erosion of the binary image and setting it as the foreground
    cv::dilate(imgthresh, bgt, cv::Mat(), cv::Point(-1, -1), 4); //dilation of the binary image to reduce the background region
    cv::threshold(bgt, bg, 1, 128, CV_THRESH_BINARY); //we get the background by setting the threshold to 1
    cv::Mat markers = cv::Mat::zeros(src.size(), CV_32SC1); //initializing the markers with a size same as the source image and setting its data type as 32-bit Single channel
    cv::add(fg, bg, markers); //setting the foreground and background as markers                                                                
    cv::Mat mask = cv::Mat::zeros(markers.size(), CV_8UC1);
    markers.convertTo(mask, CV_8UC1);    //converting the 32-bit single channel marker to a 8-bit single channel
    cv::Mat mthresh;
    cv::threshold(mask, mthresh, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); //threshold further the mask to reduce the noise
    // cv::erode(mthresh,mthresh,cv::Mat(), cv::Point(-1,-1),2);
    cv::Mat result;
    cv::bitwise_and(src, src, result, mthresh);  //use the mask to subtrack the banana from the background
    for (int x = 0; x < result.rows; x++) { //changing the black background to white
        for (int y = 0; y < result.cols; y++) {
            if (result.at<Vec3b>(x, y) == Vec3b(0, 0, 0)){
                result.at<Vec3b>(x, y)[0] = 255;
                result.at<Vec3b>(x, y)[1] = 255;
                result.at<Vec3b>(x, y)[2] = 255;
            }
        }
    }

这是我的结果:

【问题讨论】:

  • 这是结果图像 [link] (imgur.com/KG619PS) 我还不太熟悉分割的工作原理,所以请多多包涵 :)
  • 我也应该为此使用轮廓或任何其他技术吗?
  • 这张图片实际上看起来像是一个简单的阈值示例。您是否尝试过单个简单的二进制阈值并在组合 Otsu 过滤器之前使用阈值?

标签: c++ opencv image-segmentation


【解决方案1】:

由于背景接近灰色,请尝试使用色调通道和饱和度通道而不是灰度图像。
您可以轻松获得它们。

cv::Mat hsv;
cv::cvtColor(src, hsv, CV_BGR2HSV);
std::vector<cv::Mat> channels;
cv::split(src, channels);

cv::Mat hue = channels[0];
cv::Mat saturation = channels[1];

// If you want to combine those channels, use this code.
cv::Mat hs = cv::Mat::zeros(src.size(), CV_8U);
for(int r=0; r<src.rows; r++) {
    for(int c=0; c<src.cols; c++) {
        int hp = h.at<uchar>(r,c);
        int sp = s.at<uchar>(r,c);
        hs.at<uchar>(r, c) = static_cast<uchar>((h+s)>>1);
    }
}

【讨论】:

  • 我能问一下为什么在 hsv 中吗?我问的很多人也说在hsv色彩空间中更容易,但他们甚至没有告诉我原因,伤心。
  • @HarveyC en.wikipedia.org/wiki/HSL_and_HSV 看看这里。简而言之,Hue 表示“颜色方向”,Saturation 表示“颜色强度”。香蕉大多是黄色的,所以香蕉地区的色调大多相似。
【解决方案2】:

adaptiveThreshold() 应该比仅仅 level-cut threshold() 工作得更好,因为它不考虑绝对颜色级别,而是考虑被检查点周围小区域的颜色变化。

尝试用自适应阈值替换。

【讨论】:

    【解决方案3】:

    使用礼帽而不是仅仅腐蚀/膨胀。它会同时处理背景变化。

    那么在您的情况下,一个简单的阈值应该足以进行准确的分割。否则,您可以将其与分水岭结合起来。

    (我会尽快分享一些图片)。

    【讨论】:

      【解决方案4】:

      谢谢大家,我试着采纳你的建议并想出了这个

      但是,正如您所看到的,仍然有一些背景,任何如何进一步“清理”这些的想法,我尝试进一步设置阈值,但它仍然会有这些位。我想出的代码如下,我深表歉意如果变量和编码风格有些混乱,没有时间对它们进行正确排序。

      #include <stdio.h>
      #include <iostream>
      #include <opencv2\core.hpp>
      #include <opencv2\opencv.hpp>
      #include <opencv2\highgui.hpp>
      
      using namespace cv;
      using namespace std;
      
      Mat COLOR_MAX(Scalar(65, 255, 255));
      Mat COLOR_MIN(Scalar(15, 45, 45));
      
      
      int main(int argc, char** argv){
      
      Mat   src,hsv_img,mask,gray_img,initial_thresh;
      Mat   second_thresh,add_res,and_thresh,xor_thresh;
      Mat   result_thresh,rr_thresh,final_thresh;
      // Load source Image
      src = imread("sample11.jpg");
      imshow("Original Image", src);
      cvtColor(src,hsv_img,CV_BGR2HSV);
      imshow("HSV Image",hsv_img);
      
      //imwrite("HSV Image.jpg", hsv_img);
      
      inRange(hsv_img,COLOR_MIN,COLOR_MAX, mask);
      imshow("Mask Image",mask);
      
      cvtColor(src,gray_img,CV_BGR2GRAY);
      adaptiveThreshold(gray_img, initial_thresh, 255,ADAPTIVE_THRESH_GAUSSIAN_C,CV_THRESH_BINARY_INV,257,2);
      imshow("AdaptiveThresh Image", initial_thresh);
      
      add(mask,initial_thresh,add_res);
      erode(add_res, add_res, Mat(), Point(-1, -1), 1);
      dilate(add_res, add_res, Mat(), Point(-1, -1), 5);
      imshow("Bitwise Res",add_res);
      
      threshold(gray_img,second_thresh,170,255,CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
      imshow("TreshImge", second_thresh);
      
      bitwise_and(add_res,second_thresh,and_thresh);
      imshow("andthresh",and_thresh);
      
      bitwise_xor(add_res, second_thresh, xor_thresh);
      imshow("xorthresh",xor_thresh);
      
      bitwise_or(and_thresh,xor_thresh,result_thresh);
      imshow("Result image", result_thresh);
      
      bitwise_and(add_res,result_thresh,final_thresh);
      imshow("Final Thresh",final_thresh);
      erode(final_thresh, final_thresh, Mat(), Point(-1,-1),5);
      
      bitwise_and(src,src,rr_thresh,final_thresh);
      imshow("Segmented Image", rr_thresh);
      imwrite("Segmented Image.jpg", rr_thresh);
      
      waitKey(0);
      return 1;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-21
        • 1970-01-01
        • 2015-07-16
        • 2017-09-04
        • 2013-01-03
        • 2021-09-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多