使用带有新 OpenCV C++ 接口的距离变换出现问题/如何确保 Mat 是二进制掩码?
Posted
技术标签:
【中文标题】使用带有新 OpenCV C++ 接口的距离变换出现问题/如何确保 Mat 是二进制掩码?【英文标题】:Problem using distance transform with new OpenCV C++ interface / How to ensure that Mat is a binary mask? 【发布时间】:2010-10-26 09:03:00 【问题描述】:我正在移植我的代码以使用新的 OpenCV C++ 接口。我喜欢严格键入所有内容的可能性,因此从模板类中派生我所有的图像和矩阵:
Mat_<type> var;
现在我在使用 distanceTransform 函数时遇到了问题。我的代码是这样的:
Mat_<float> imgGray;
Mat_<unsigned char> imgBinary;
Mat_<float> imgDistance;
// ... fill imgGray with data ...
threshold(imgGray, imgBinary, 0.25, 255, CV_THRESH_BINARY);
distanceTransform(imgBinary, imgDistance, CV_DIST_L2, CV_DIST_MASK_PRECISE);
distanceTransform 失败。它给出了以下错误:
未知函数中不支持的格式或格式组合(源图像必须为 8uC1,距离图必须为 32fC1(或 8uC1,如果是简单的 L1 距离变换)),文件........\src\ cv\cvdistransform.cpp,第 730 行
我发现问题出在源参数上。它没有通过 CV_IS_MASK_ARR(src) 测试。
据我了解,阈值调用在 imgBinary 上创建以分配内存。所以我无法控制 imgBinary 矩阵的确切类型(应该是 CV_8UC1),对吗?如何确保 imgBinary 是正确的二进制掩码以使 distanceTransform 满意?
感谢您的帮助!
干杯,罗伯特
【问题讨论】:
ok 问题是threshold得到float数据时,输出也是float。当使用比较(或更短:imgBinary = imgGray > 0.25)时,代码可以正常工作。 但是:当使用严格类型的矩阵时,我会在尝试使用另一种数据类型时出现异常(这就是我使用严格类型矩阵的原因......)。阈值能够将 Mat_如果您愿意,可以查看下面的代码。这是带有 OpenCV C++ API 的新版本 DT
//#define CV_NO_BACKWARD_COMPATIBILITY
// if you compile the program under Windows and MSVC2008/2005
#if defined WIN32 || defined _MSC_VER
#pragma warning(disable:4786)
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#define _SCL_SECURE_NO_WARNINGS
#endif
#include <iostream>
#include "cv.h"
#include "cvaux.h"
#include "highgui.h"
#define DEMO_MIXED_API_USE 1
using namespace cv;
using namespace std;
char wndname[] = "Distance transform";
char tbarname[] = "Threshold";
int mask_size = CV_DIST_MASK_5;
int build_voronoi = 0;
int edge_thresh = 100;
int dist_type = CV_DIST_L1;
// The output and temporary images
Mat dist;
Mat dist8u1;
Mat dist8u2;
Mat dist8u;
Mat dist32s;
Mat gray;
Mat edge;
Mat labels;
// threshold trackbar callback
void on_trackbar( int dummy, void *)
static const uchar colors[][3] =
0,0,0,
255,0,0,
255,128,0,
255,255,0,
0,255,0,
0,128,255,
0,255,255,
0,0,255,
255,0,255
;
int msize = mask_size;
int _dist_type = build_voronoi ? CV_DIST_L2 : dist_type;
threshold( gray, edge, (double)edge_thresh, (double)edge_thresh, CV_THRESH_BINARY );
if( build_voronoi )
msize = CV_DIST_MASK_5;
if( _dist_type == CV_DIST_L1 )
distanceTransform( edge, dist, _dist_type, msize );
else
build_voronoi ? distanceTransform( edge, dist, labels, _dist_type, msize ) : distanceTransform( edge, dist, _dist_type, msize ) ;
if( !build_voronoi )
// begin "painting" the distance transform result
dist.convertTo( dist, dist.type(), 5000.0, 0 ); //before--> cvConvertScale( dist, dist, 5000.0, 0 );
pow( dist, 0.5, dist ); //before--> cvPow(dist, dist, 0.5);
dist.convertTo( dist32s, dist32s.type(), 1.0, 0.5 ); //before--> cvConvertScale( dist, dist32s, 1.0, 0.5 );
bitwise_and( dist32s, Scalar::all(255), dist32s, Mat() ); //before--> cvAndS( dist32s, ScalarAll(255), dist32s, 0 );
dist32s.convertTo(dist8u1, dist8u1.type(), 1, 0 ); //before--> cvConvertScale( dist32s, dist8u1, 1, 0 );
dist32s.convertTo( dist32s, dist32s.type(), -1, 0 ); //before--> cvConvertScale( dist32s, dist32s, -1, 0 );
add( dist32s, Scalar::all(255), dist32s, Mat() ); //before--> cvAddS( dist32s, cvScalarAll(255), dist32s, 0 );
dist32s.convertTo( dist8u2, dist8u2.type(), 1, 0 ); //before--> cvConvertScale( dist32s, dist8u2, 1, 0 );
vector<Mat> Out(3);
Out[0] = dist8u1;
Out[1] = dist8u2;
Out[2] = dist8u2;
merge( Out, dist8u ); //before--> cvMerge( dist8u1, dist8u2, dist8u2, 0, dist8u );
// end "painting" the distance transform result
else
int i, j;
for( i = 0; i < labels.rows; i++ )
int* ll = labels.ptr<int>(i); //before--> (int*)(labels->imageData + i*labels->widthStep)
float* dd = dist.ptr<float>(i); //before--> (float*)(dist->imageData + i*dist->widthStep)
uchar* d = dist8u.ptr<uchar>(i); //before--> (uchar*)(dist8u->imageData + i*dist8u->widthStep)
for( j = 0; j < labels.cols; j++ )
int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1;
int b = cvRound(colors[idx][0]); // if there is an option to cvRound in the new OpenCV C++ API, tell me please
int g = cvRound(colors[idx][1]);
int r = cvRound(colors[idx][2]);
d[j*3] = saturate_cast<uchar>(b); //before--> (uchar)b;
d[j*3+1] = saturate_cast<uchar>(g); //before--> (uchar)g;
d[j*3+2] = saturate_cast<uchar>(r); //before--> (uchar)r;
imshow( wndname, dist8u ); //before--> cvShowImage( wndname, dist8u );
int main( int argc, char* argv[] )
const char* filename = (argc == 2 ? argv[1] : "Debug/stuff.jpg");//lena.jpg
gray = imread( filename, 0 ); // -1 loads image full(3 channels + alpha) , 0 only in grayscale
if( gray.empty() )
return -1;
cout << "Hot keys: \n"
<< "\tESC - quit the program\n"
<< "\tC - use C/Inf metric\n"
<< "\tL1 - use L1 metric\n"
<< "\tL2 - use L2 metric\n"
<< "\t3 - use 3x3 mask\n"
<< "\t5 - use 5x5 mask\n"
<< "\t0 - use precise distance transform\n"
<< "\tv - switch Voronoi diagram mode on/off\n"
<< "\tSPACE - loop through all the modes\n" << endl;
dist = Mat( gray.size(), CV_32FC1 ); //dist = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32F, 1 );
dist8u1 = gray.clone(); //dist8u1 = cvCloneImage( gray );
dist8u2 = gray.clone(); //dist8u2 = cvCloneImage( gray );
dist8u = Mat( gray.size(), CV_8UC3 ); //dist8u = cvCreateImage( cvGetSize(gray), IPL_DEPTH_8U, 3 );
dist32s = Mat( gray.size(), CV_32SC1 ); //dist32s = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );
edge = gray.clone(); //edge = cvCloneImage( gray );
labels = Mat( gray.size(), CV_32SC1 ); //labels = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );
namedWindow( wndname, 1 );
createTrackbar( tbarname, wndname, &edge_thresh, 255, on_trackbar );
for(;;)
int c;
// Call to update the view
on_trackbar(0, 0);
c = waitKey(0);
if( (char)c == 27 )
break;
if( (char)c == 'c' || (char)c == 'C' )
dist_type = CV_DIST_C;
else if( (char)c == '1' )
dist_type = CV_DIST_L1;
else if( (char)c == '2' )
dist_type = CV_DIST_L2;
else if( (char)c == '3' )
mask_size = CV_DIST_MASK_3;
else if( (char)c == '5' )
mask_size = CV_DIST_MASK_5;
else if( (char)c == '0' )
mask_size = CV_DIST_MASK_PRECISE;
else if( (char)c == 'v' )
build_voronoi ^= 1;
else if( (char)c == ' ' )
if( build_voronoi )
build_voronoi = 0;
mask_size = CV_DIST_MASK_3;
dist_type = CV_DIST_C;
else if( dist_type == CV_DIST_C )
dist_type = CV_DIST_L1;
else if( dist_type == CV_DIST_L1 )
dist_type = CV_DIST_L2;
else if( mask_size == CV_DIST_MASK_3 )
mask_size = CV_DIST_MASK_5;
else if( mask_size == CV_DIST_MASK_5 )
mask_size = CV_DIST_MASK_PRECISE;
else if( mask_size == CV_DIST_MASK_PRECISE )
build_voronoi = 1;
return 0;
【讨论】:
以上是关于使用带有新 OpenCV C++ 接口的距离变换出现问题/如何确保 Mat 是二进制掩码?的主要内容,如果未能解决你的问题,请参考以下文章