C++ 和 OpenCV 4.5.3 -(-215:断言失败)

C++ and OpenCV 4.5.3 - (-215: Assertion failed)

问题:分水岭算法

我开始了应用程序项目,用于图像处理,使用 OpenCv 4.5.3 和 Swift(使用 C++)。我正在与水影藻类作斗争。很长一段时间......我不知道我做错了什么。只是不知道...

错误:

libc++abi.dylib: terminating with uncaught exception of type cv::Exception: OpenCV(4.5.3)
/Volumes/build-storage/build/master_iOS-mac/opencv/modules/imgproc/src/segmentation.cpp:161: 
error: (-215:Assertion failed) src.type() 
== CV_8UC3 && dst.type() == CV_32SC1 in function 'watershed'

terminating with uncaught exception of type cv::Exception: OpenCV(4.5.3) 
/Volumes/build-storage/build/master_iOS-mac/opencv/modules/imgproc/src/segmentation.cpp:161: error: 
(-215:Assertion failed) src.type() 
== CV_8UC3 && dst.type() == CV_32SC1 in function 'watershed'

在openCv的分水岭定义中我们可以发现:

@param image Input 8-bit 3-channel image.
@param markers Input/output 32-bit single-channel image (map) of markers. It should have the same size as image .

代码

+(UIImage *) watershed:(UIImage *)src{
 cv::Mat img, mask;
    UIImageToMat(src, img);
    // Change the background from white to black, since that will help later to extract
      // better results during the use of Distance Transform
    cv::inRange(img, cv::Scalar(255,255,255), cv::Scalar(255,255,255), mask);
    img.setTo(cv::Scalar(0,0,0), mask);
    
    // Create a kernel that we will use to sharpen our image
    // an approximation of second derivative, a quite strong kernel
    cv::Mat kernel = (cv::Mat_<float>(3,3) <<
                      1, 1, 1,
                      1, -8, 1,
                      1, 1, 1);
    
    // do the laplacian filtering as it is
        // well, we need to convert everything in something more deeper then CV_8U
        // because the kernel has some negative values,
        // and we can expect in general to have a Laplacian image with negative values
        // BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
        // so the possible negative number will be truncated
    cv::Mat lapl;
    cv::filter2D(img, lapl, CV_32F, kernel);
    
    cv::Mat sharp;
    img.convertTo(sharp, CV_32F);
    cv::Mat result = sharp - lapl;
    
    // convert back to 8bits gray scale
    result.convertTo(result, CV_8UC3);
    lapl.convertTo(lapl, CV_8UC3);
    
    cv::Mat bw;
    cv::cvtColor(result, bw, cv::COLOR_BGR2GRAY);
    cv::threshold(bw, bw, 40, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    
    // Perform the distance transform algorithm
      cv::Mat dist;
      cv::distanceTransform(bw, dist, cv::DIST_L2, cv::DIST_MASK_3);
    
    // Normalize the distance image for range = {0.0, 1.0}
     // so we can visualize and threshold it
    cv::normalize(dist, dist, 0, 1.0, cv::NORM_MINMAX);
    
    // Threshold to obtain the peaks
      // This will be the markers for the foreground objects
      cv::threshold(dist, dist, 0.4, 1.0, cv::THRESH_BINARY);
    
    // Dilate a bit the dist image
    cv::Mat kernel1 = cv::Mat::ones(3, 3, CV_8U);
      dilate(dist, dist, kernel1);
   
      // Create the CV_8U version of the distance image
      // It is needed for findContours()
    cv::Mat dist_8u;
      dist.convertTo(dist_8u, CV_8U);
      // Find total markers
      std::vector<std::vector<cv::Point> > contours;
    findContours(dist_8u, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
      // Create the marker image for the watershed algorithm
    cv::Mat markers = cv::Mat::zeros(dist.size(), CV_32S);
      // Draw the foreground markers
      for (size_t i = 0; i < contours.size(); i++)
      {
          drawContours(markers, contours, static_cast<int>(i), cv::Scalar(static_cast<int>(i)+1), -1);
      }
      // Draw the background marker
      circle(markers, cv::Point(5,5), 3, cv::Scalar(255), -1);
      cv::Mat markers8u;
      markers.convertTo(markers8u, CV_8U, 10);
      
      // Perform the watershed algorithm
      watershed(result, markers);
     
     
    return MatToUIImage(result);
}

您可以清楚地看到,变量具有正确的类型,如 descr 中所示。功能:

 result.convertTo(result, CV_8UC3);
cv::Mat markers = cv::Mat::zeros(dist.size(), CV_32S);

convertTo也不能添加通道,也不能reduce/convert图像到通道数量较少的图像。 这种情况下的关键是使用 :

 cvtColor(src, src, COLOR_BGRA2BGR); // change 4 to 3 channels