cvThreshold||cvLine||cvLoadImage,cvCreateImage之灰度

本文详细介绍了如何使用OpenCV将彩色图片转化为灰度图,并提供了彩色图像基本绘图指令的使用方法,包括绘制矩形、圆形、线段、多边形及文本标注。


【Q1】怎么样用opencv将彩色图片转化成像素值只有0和255的灰度图?

进行灰度化,IplImage* pImg = cvLoadImage( "C:\\1.bmp", 0 );    这样图像已经灰度化,然后调用cvThreshold(image, image, 125, 255, CV_THRESH_BINARY);   就可以了,125那里是你所用的阈值,这就是最简单的二值化,你要用ostu,或者别的高级一点的,就要自己写函数了


// Truncate values above 100.
  cvThreshold( s, dst, 100, 255, CV_THRESH_TRUNC );//对大于100的像素值进行截断,大于100则为255,不大于100的为原值
  

【Q2】cvLine画直线

CvScalar color = CV_RGB(50,0,250);
cvLine( img1, p1, q1, color, 1, CV_AA, 0 );
cvLine( img1, p2, q2, color, 1, CV_AA, 0 );
cvLine( img1, p1, p2, color, 1, CV_AA, 0 );
cvLine( img1, q1, q2, color, 1, CV_AA, 0 );

or

cvLine(image,epipolarLinePoint1,epipolarLinePoint2,CV_RGB(0,255,0));

 

cv::Line

CV_RGB 创建一个色彩值. #define CV_RGB( r, g, b ) [编辑] cvScalar( (b), (g), (r) ) Line 绘制连接两个点的线段 void cvLine( CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness=1, int line_type=8, int shift=0 ); img 图像。 pt1 线段的第一个端点。 pt2 线段的第二个端点。 color 线段的颜色。 thickness 线段的粗细程度。 line_type 线段的类型。 8 (or 0) - 8-connected line(8 邻接)连接 线。 4 - 4-connected line(4 邻接)连接线。 CV_AA - antialiased 线条。 shift 坐标点的小数点位数。 函数 cvLine 在图像中的点 1 和点 2 之间画一条线段。线段被图像或感兴趣的 矩形(ROI rectangle)所裁剪。对于具有整数坐标的 non-antialiasing 线条, 使用 8-连接或者 4-连接 Bresenham 算法。画粗线条时结尾是圆形的。画 antialiased 线条使用高斯滤波。要指定线段颜色,用户可以使用使用宏 CV_RGB( r, g, b )。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

cvLoadImage函数使用方法 

四、图像处理
 
1、图像的内存分配与释放

(1) 分配内存给一幅新图像:

IplImage* cvCreateImage(CvSize size, int depth, int channels);

    size: cvSize(width,height);

    depth: 像素深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,

   IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F, IPL_DEPTH_64F

    channels: 像素通道数. Can be 1, 2, 3 or 4.

        各通道是交错排列的. 一幅彩色图像的数据排列格式如下:

            b0 g0 r0 b1 g1 r1 ...

示例:

// Allocate a 1-channel byte image
IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
 
// Allocate a 3-channel float image
IplImage* img2=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);

 
(2) 释放图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
cvReleaseImage(&img);

 
(3) 复制图像:

IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
IplImage* img2;
img2=cvCloneImage(img1);  // 注意通过cvCloneImage得到的图像
                      // 也要用 cvReleaseImage 释放,否则容易产生内存泄漏

 
(4) 设置/获取感兴趣区域ROI:

void  cvSetImageROI(IplImage* image, CvRect rect);
void  cvResetImageROI(IplImage* image);
CvRect cvGetImageROI(const IplImage* image);

大多数OpenCV函数都支持 ROI.
 
(5) 设置/获取感兴趣通道COI:

void cvSetImageCOI(IplImage* image, int coi); // 0=all
int cvGetImageCOI(const IplImage* image);

大多数OpenCV函数不支持 COI.
 
2、图像读写
 
(1) 从文件中读入图像:

IplImage* img=0;
  img=cvLoadImage(fileName);
  if(!img) printf("Could not load image file: %s\n",fileName);

 支持的图像格式: BMP, DIB, JPEG, JPG, JPE, PNG, PBM, PGM, PPM,
                          SR, RAS, TIFF, TIF

OpenCV默认将读入的图像强制转换为一幅三通道彩色图像. 不过可以按以下方法修改读入方式:

img=cvLoadImage(fileName,flag);

 flag: >0 将读入的图像强制转换为一幅三通道彩色图像
       =0 将读入的图像强制转换为一幅单通道灰度图像
       <0 读入的图像通道数与所读入的文件相同.

 
(2) 保存图像:

if(!cvSaveImage(outFileName,img)) printf("Could not save: %s\n", outFileName);

保存的图像格式由 outFileName 中的扩展名确定.
 
3、访问图像像素
 
(1) 假设你要访问第k通道、第i行、第j列的像素。
 
(2) 间接访问: (通用,但效率低,可访问任意格式的图像)

    * 对于单通道字节型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
CvScalar s;
s=cvGet2D(img,i,j); // get the (i,j) pixel value
printf("intensity=%f\n",s.val[0]);
s.val[0]=111;
cvSet2D(img,i,j,s); // set the (i,j) pixel value

    * 对于多通道字节型/浮点型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
CvScalar s;
s=cvGet2D(img,i,j); // get the (i,j) pixel value
printf("B=%f, G=%f, R=%f\n",s.val[0],s.val[1],s.val[2]);
s.val[0]=111;
s.val[1]=111;
s.val[2]=111;
cvSet2D(img,i,j,s); // set the (i,j) pixel value

 
(3) 直接访问: (效率高,但容易出错)

    * 对于单通道字节型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
((uchar *)(img->imageData + i*img->widthStep))[j]=111;

    * 对于多通道字节型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R

    * 对于多通道浮点型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R

 
(4) 基于指针的直接访问: (简单高效)

    * 对于单通道字节型图像:

IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
int height     = img->height;
int width      = img->width;
int step       = img->widthStep/sizeof(uchar);
uchar* data    = (uchar *)img->imageData;
data[i*step+j] = 111;

    * 对于多通道字节型图像:

IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
int height     = img->height;
int width      = img->width;
int step       = img->widthStep/sizeof(uchar);
int channels   = img->nChannels;
uchar* data    = (uchar *)img->imageData;
data[i*step+j*channels+k] = 111;

    * 对于多通道浮点型图像(假设图像数据采用4字节(32位)行对齐方式):

IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
int height     = img->height;
int width      = img->width;
int step       = img->widthStep/sizeof(float);
int channels   = img->nChannels;
float * data    = (float *)img->imageData;
data[i*step+j*channels+k] = 111;

 
(5) 基于 c++ wrapper 的直接访问: (更简单高效)

    * 首先定义一个 c++ wrapper ‘Image’,然后基于Image定义不同类型的图像:

template<class T> class Image
{
  private:
  IplImage* imgp;
  public:
  Image(IplImage* img=0) {imgp=img;}
  ~Image(){imgp=0;}
  void operator=(IplImage* img) {imgp=img;}
  inline T* operator[](const int rowIndx) {
    return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));}
};
 
typedef struct{
  unsigned char b,g,r;
} RgbPixel;
 
typedef struct{
  float b,g,r;
} RgbPixelFloat;
 
typedef Image<RgbPixel>       RgbImage;
typedef Image<RgbPixelFloat>  RgbImageFloat;
typedef Image<unsigned char>  BwImage;
typedef Image<float>          BwImageFloat;

    * 对于单通道字节型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
BwImage imgA(img);
imgA[i][j] = 111;

    * 对于多通道字节型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
RgbImage  imgA(img);
imgA[i][j].b = 111;
imgA[i][j].g = 111;
imgA[i][j].r = 111;

    * 对于多通道浮点型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
RgbImageFloat imgA(img);
imgA[i][j].b = 111;
imgA[i][j].g = 111;
imgA[i][j].r = 111;

 
4、图像转换
 
(1) 字节型图像的灰度-彩色转换:

cvConvertImage(src, dst, flags=0);

 src = float/byte grayscale/color image
 dst = byte grayscale/color image
 flags = CV_CVTIMG_FLIP     (垂直翻转图像)
         CV_CVTIMG_SWAP_RB  (置换 R 和 B 通道)

 
(2) 彩色图像->灰度图像:

// Using the OpenCV conversion:
cvCvtColor(cimg,gimg,CV_BGR2GRAY); // cimg -> gimg
 
// Using a direct conversion:
for(i=0;i<cimg->height;i++) for(j=0;j<cimg->width;j++)
  gimgA[i][j]= (uchar)(cimgA[i][j].b*0.114 +
                       cimgA[i][j].g*0.587 +
                       cimgA[i][j].r*0.299);

 
(3) 不同彩色空间之间的转换:

cvCvtColor(src,dst,code); // src -> dst

 code    = CV_<X>2<Y>
 <X>/<Y> = RGB, BGR, GRAY, HSV, YCrCb, XYZ, Lab, Luv, HLS

e.g.: CV_BGR2GRAY, CV_BGR2HSV, CV_BGR2Lab
 
5、绘图指令
 
(1) 绘制矩形:

// 在点 (100,100) 和 (200,200) 之间绘制一矩形,边线用红色、宽度为 1
cvRectangle(img, cvPoint(100,100), cvPoint(200,200), cvScalar(255,0,0), 1);

 
(2) 绘制圆形:

// 圆心为(100,100)、半径为20. 圆周绿色、宽度为1
cvCircle(img, cvPoint(100,100), 20, cvScalar(0,255,0), 1);

 
(3) 绘制线段:

// 在 (100,100) 和 (200,200) 之间、线宽为 1 的绿色线段
cvLine(img, cvPoint(100,100), cvPoint(200,200), cvScalar(0,255,0), 1);

 
(4) 绘制一组线段:

CvPoint  curve1[]={10,10,  10,100,  100,100,  100,10};
CvPoint  curve2[]={30,30,  30,130,  130,130,  130,30,  150,10};
CvPoint* curveArr[2]={curve1, curve2};
int      nCurvePts[2]={4,5};
int      nCurves=2;
int      isCurveClosed=1;
int      lineWidth=1;
 
cvPolyLine(img,curveArr,nCurvePts,nCurves,isCurveClosed,cvScalar(0,255,255),lineWidth);
 
void cvPolyLine( CvArr* img, CvPoint** pts, int* npts, int contours, int is_closed,
                          CvScalar color, int thickness=1, int line_type=8, int shift=0 );
img       图像。
pts       折线的顶点指针数组。
npts     折线的定点个数数组。也可以认为是pts指针数组的大小
contours   折线的线段数量。
is_closed  指出多边形是否封闭。如果封闭,函数将起始点和结束点连线。
color         折线的颜色。
thickness  线条的粗细程度。
line_type  线段的类型。参见cvLine。
shift          顶点的小数点位数

 
(5) 绘制一组填充颜色的多边形:

cvFillPoly(img,curveArr,nCurvePts,nCurves,cvScalar(0,255,255));
 
cvFillPoly用于一个单独被多边形轮廓所限定的区域内进行填充。函数可以填充复杂的区域,例如,有漏洞的区域和有交叉点的区域等等。
void cvFillPoly( CvArr* img, CvPoint** pts, int* npts, int contours,CvScalar color, int line_type=8, int shift=0 );
img           图像。
pts           指向多边形的数组指针。
npts         多边形的顶点个数的数组。
contours   组成填充区域的线段的数量。
color         多边形的颜色。
line_type  组成多边形的线条的类型。
shift          顶点坐标的小数点位数。

 
(6) 文本标注:

CvFont font;
double hScale=1.0;
double vScale=1.0;
int    lineWidth=1;
cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX|CV_FONT_ITALIC, hScale,vScale,0,lineWidth);
 
cvPutText (img,"My comment",cvPoint(200,400), &font, cvScalar(255,255,0));

其它可用的字体类型有: CV_FONT_HERSHEY_SIMPLEX, CV_FONT_HERSHEY_PLAIN, CV_FONT_HERSHEY_DUPLEX, CV_FONT_HERSHEY_COMPLEX, CV_FONT_HERSHEY_TRIPLEX, CV_FONT_HERSHEY_COMPLEX_SMALL, CV_FONT_HERSHEY_SCRIPT_SIMPLEX, CV_FONT_HERSHEY_SCRIPT_COMPLEX,

 

 

/////////////////////////////////////////////////  参考  /////////////////

     cvLoadImage( filename, -1 ); 默认读取图像的原通道数

  cvLoadImage( filename, 0 ); 强制转化读取图像为灰度图

  cvLoadImage( filename, 1 ); 读取彩色图

  例:将读入图像强制转换为灰度图像显示

  #include <highgui.h>

  #include <cv.h>

  int main(int argc, char **argv)

  {

  if (argc != 2)

  return -1;

  /*强制转换为灰度图像*/

  IplImage *img = cvLoadImage(argv[1], 0);

  cvNamedWindow("example");

  cvShowImage("example", img);

  cvWaitKey(0);

  cvReleaseImage(&img);

  cvDestroyWindow("example");

  return 0;

  }

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

不错的博客!!!

1.  OpenCV的IplImage数据结构的各成员变量的含义      如何访问data

http://www.cppblog.com/lixiaona0417/archive/2011/03/05/141155.html

 

2.  图像的像素点操作【OpenCV学习笔记3】 

http://blog.youkuaiyun.com/superdont/article/details/5910270


3.  

文件的保存【OpenCV学习笔记4】

http://blog.youkuaiyun.com/superdont/article/details/5910280


  1. /*   
  2. 功能:读入图像文件,做图像反转,然后显示图像在屏幕上 
  3. */  
  4. #include "stdafx.h"  
  5. #include <stdlib.h>  
  6. #include <stdio.h>  
  7. #include <math.h>  
  8. #include <cv.h>  
  9. #include <highgui.h>  
  10. int main(int argc, char *argv[])  
  11. {  
  12.     IplImage* img = 0;   
  13.     int height,width,step,channels;  
  14.     uchar *data;  
  15.     int i,j,k;  
  16.     if(argc<2)  
  17.     {  
  18.         printf("Usage: main <image-file-name>/n/7");  
  19.         exit(0);  
  20.     }  
  21.     // 载入图像    
  22.     img=cvLoadImage(argv[1],-1);  
  23.     if(!img)  
  24.     {  
  25.         printf("Could not load image file: %s/n",argv[1]);  
  26.         exit(0);  
  27.     }  
  28.     // 获取图像信息  
  29.     height    = img->height;    
  30.     width     = img->width;    
  31.     step      = img->widthStep;    
  32.     channels  = img->nChannels;  
  33.     data      = (uchar *)img->imageData;  
  34.     printf("Processing a %dx%d image with %d channels/n",height,width,channels);   
  35.     // 创建窗口  
  36.     cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);   
  37.     cvMoveWindow("mainWin", 100, 100);  
  38.     // 反转图像  
  39.     for(i=0;i<height;i++)   
  40.         for(j=0;j<width;j++)   
  41.             for(k=0;k<channels;k++)  
  42.                 data[i*step+j*channels+k]=255-data[i*step+j*channels+k];  
  43.     // 显示图像  
  44.     cvShowImage("mainWin", img );  
  45.     cvWaitKey(0);  
  46.     cvReleaseImage(&img );  
  47.     printf("height=%d  width=%d step=%d channels=%d",height,width,step,channels);  
  48.     return 0;  
  49. }  
  50.   
  51. //  
  52. //IplImage* cvLoadImage( const char* filename, int flags=CV_LOAD_IMAGE_COLOR );  
  53. //filename   
  54. //要被读入的文件的文件名。  
  55. //flags   
  56. //指定读入图像的颜色和深度:  
  57. //指定的颜色可以将输入的图片转为3信道(CV_LOAD_IMAGE_COLOR)也即彩色(>0),   
  58. //单信道 (CV_LOAD_IMAGE_GRAYSCALE)也即灰色(=0), 或者保持不变(CV_LOAD_IMAGE_ANYCOLOR)(<0)。  
  59. //深度指定输入的图像是否转为每个颜色信道每象素8位,(OpenCV的早期版本一样),或者同输入的图像一样保持不变。  
  60. //选中CV_LOAD_IMAGE_ANYDEPTH,则输入图像格式可以为8位无符号,16位无符号,32位有符号或者32位浮点型。  
  61. //如果输入有冲突的标志,将采用较小的数字值。  
  62. //比如CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYCOLOR 将载入3信道图。  
  63. //CV_LOAD_IMAGE_ANYCOLOR和CV_LOAD_IMAGE_UNCHANGED是等值的。  
  64. //但是,CV_LOAD_IMAGE_ANYCOLOR有着可以和CV_LOAD_IMAGE_ANYDEPTH同时使用的优点,  
  65. //所以CV_LOAD_IMAGE_UNCHANGED不再使用了。  
  66. //如果想要载入最真实的图像,选择CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR。  
  67. //函数cvLoadImage从指定文件读入图像,返回读入图像的指针。目前支持如下文件格式:  
  68. //Windows位图文件 - BMP, DIB;  
  69. //JPEG文件 - JPEG, JPG, JPE;  
  70. //便携式网络图片 - PNG;  
  71. //便携式图像格式 - PBM,PGM,PPM;  
  72. //Sun rasters - SR,RAS;  
  73. //TIFF文件 - TIFF,TIF;  
  74. //OpenEXR HDR 图片 - EXR;  
  75. //JPEG 2000 图片- jp2。  
  76. //=======================================================================================  
  77. //IplImage  
  78. //  
  79. //IPL 图像头  
  80. //typedef struct _IplImage  
  81. //    {  
  82. //        int  nSize;         /* IplImage大小,=sizeof(IplImage)*/  
  83. //        int  ID;            /* 版本 (=0)*/  
  84. //        int  nChannels;     /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */  
  85. //        int  alphaChannel;  /* 被OpenCV忽略 */  
  86. //        int  depth;         /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,  
  87. //                               IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */  
  88. //        char colorModel[4]; /* 被OpenCV忽略 */  
  89. //        char channelSeq[4]; /* 被OpenCV忽略 */  
  90. //        int  dataOrder;     /* 0 - 交叉存取颜色通道,对三通道RGB图像,像素存储顺序为BGR BGR BGR ... BGR;  
  91. //                                     1 - 分开的颜色通道,对三通道RGB图像,像素存储顺序为RRR...R GGG...G BBB...B。  
  92. //                                  cvCreateImage只能创建交叉存取图像 */  
  93. //        int  origin;        /* 0 - 顶—左结构,  
  94. //                               1 - 底—左结构 (Windows bitmaps 风格) */  
  95. //        int  align;         /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */  
  96. //        int  width;         /* 图像宽像素数 */  
  97. //        int  height;        /* 图像高像素数*/  
  98. //        struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理 */  
  99. //        struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */  
  100. //        void  *imageId;     /* 同上*/  
  101. //        struct _IplTileInfo *tileInfo; /*同上*/  
  102. //        int  imageSize;     /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/  
  103. //        char *imageData;  /* 指向排列的图像数据 */  
  104. //        int  widthStep;   /* 排列的图像行大小,以字节为单位 */  
  105. //        int  BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */  
  106. //        int  BorderConst[4]; /* 同上 */  
  107. //        char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */  
  108. //    }  
  109. //    IplImage;  
  110. //IplImage结构来自于 Intel Image Processing Library(是其本身所具有的)。OpenCV 只支持其中的一个子集:  
  111. //alphaChannel 在OpenCV中被忽略。  
  112. //colorModel 和channelSeq 被OpenCV忽略。  
  113. //OpenCV颜色转换的唯一函数 cvCvtColor把原图像的颜色空间的目标图像的颜色空间作为一个参数。  
  114. //dataOrder 必须是IPL_DATA_ORDER_PIXEL (颜色通道是交叉存取),  
  115. //然而平面图像的被选择通道可以被处理,就像COI(感兴趣的通道)被设置过一样。  
  116. //align 是被OpenCV忽略的,而用 widthStep 去访问后继的图像行。  
  117. //不支持maskROI 。处理MASK的函数把他当作一个分离的参数。  
  118. //MASK在 OpenCV 里是 8-bit,然而在 IPL他是 1-bit。  
  119. //tileInfo 不支持。  
  120. //BorderMode和BorderConst是不支持的。  
  121. //每个 OpenCV 函数处理像素的邻近的像素,  
  122. //通常使用单一的固定代码边际模式。  
  123. //除了上述限制,OpenCV处理ROI有不同的要求。  
  124. //要求原图像和目标图像的尺寸或 ROI的尺寸必须  
  125. //(根据不同的操作,例如cvPyrDown 目标图像的宽(高)必须等于原图像的宽(高)除以2 ±1)  
  126. //精确匹配,而IPL处理交叉区域,如图像的大小或ROI大小可能是完全独立的。  
  127. //======================================================================  
  128. //Processing a 512x512 image with 3 channels  
  129. //height=512  width=512 step=1536 channels=3请按任意键继续. . .  
  130. //从上述关系可以看出  
  131. //在C++内图像的存储是与Matlab不一样的  
  132. //是在C++内存储的方式是按照行列方式,每一行内存储了该列(所有层)的信息。  

<think> 首先,用户的问题是关于OpenCV中的图像处理:他想了解“THRESH_BINARY_INV | THRESH_OTSU”的含义、用法及相关技术介绍。用户引用了三个站内引用,这些引用讨论了cv2.THRESH_BINARY与cv2.THRESH_OTSU的组合使用、Otsu方法的阈值分割,以及版本兼容性问题。 关键点: - 引用[1]解释了大津算法(Otsu's method),它自动确定阈值来区分前景和背景。 - 引用[2]提供了使用cv2.threshold函数的例子,特别是结合cv2.THRESH_BINARY和cv2.THRESH_OTSU。 - 引用[3]提到了版本兼容性问题,如错误“CV_THRESH_BINARY_INV was not declared”,建议修改宏定义名。 用户的问题焦点是“THRESH_BINARY_INV | THRESH_OTSU”。我需要解释这个组合的含义、用法、相关技术以及常见问题。 系统级指令: - 使用$...$格式处理行内数学表达式。 - 独立公式用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 回答结构: 1. **含义解释**:解释THRESH_BINARY_INV | THRESH_OTSU是什么。 2. **用法说明**:如何在代码中使用它,基于引用[1]和[2]。 3. **相关技术介绍**:讨论大津算法的工作原理、阈值分割基础等。 4. **兼容性问题**:提及版本差异,基于引用[3]。 5. **生成相关问题**:在结尾添加相关问题。 核心内容: - **THRESH_BINARY_INV**:这是二值化的反转版本。在标准二值化中,高于阈值的像素设为最大值(如255),低于设为0。反转版本中,高于阈值的设为0,低于设为最大值。 - **THRESH_OTSU**:大津法,自动计算阈值以最大化类间方差。 - 组合使用:| 操作符表示结合两者,即使用大津法自动确定阈值,然后应用二进制反转二值化。 代码示例:参考引用[1]和[2],给出类似代码。 - 示例:`ret, binary_image = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)` - 解释参数:image是输入灰度图像,0是占位符(被Otsu覆盖),255是最大值,标志组合。 技术背景: - **大津算法的数学原理**:它基于图像的直方图,找到阈值t使得类间方差最大。公式涉及: - 总像素数:$N$ - 前景和背景的概率分布。 - 类间方差:$\sigma_b^2(t) = \omega_0(t)\omega_1(t)(\mu_0(t) - \mu_1(t))^2$,其中$\omega_0$、$\omega_1$是权重,$\mu_0$、$\mu_1$是均值。 - 独立公式:用$$...$$格式展示关键公式。 兼容性问题: - 引用[3]提到旧版本OpenCV的宏定义差异。新版本(如OpenCV 3+)使用cv2.THRESH_BINARY_INV和cv2.THRESH_OTSU,而旧版本可能有CV_THRESH_BINARY_INV等。建议检查版本并使用正确命名。 相关问题生成: - 例如: 1. 大津算法的工作原理解释是什么? 2. THRESH_BINARY和THRESH_BINARY_INV有什么区别? 3. 如何处理OpenCV中的版本兼容性问题? 4. Otsu方法在哪些场景下不适用? 确保回答真实可靠:基于提供的引用和OpenCV文档。引用来源末尾添加标识。 中文回答:全程使用中文。 最终回答结构: 1. 介绍含义。 2. 详细解释用法。 3. 相关技术背景。 4. 兼容性提示。 5. 代码示例。 6. 相关问题。 </think> ### THRESH_BINARY_INV | THRESH_OTSU 的含义、用法及相关技术介绍 在 OpenCV 的图像处理中,`THRESH_BINARY_INV | THRESH_OTSU` 是一种组合阈值分割方法,用于自动将灰度图像二值化(即转换为黑白图像)。下面我将逐步解释其含义、用法、技术背景及常见问题。 #### 1. **组合方法的含义** - **THRESH_OTSU**:基于大津算法(Otsu's method),它能自动计算图像的最佳阈值。该算法分析图像的直方图分布,找到使前景(如物体)和背景之间的类间方差最大化的阈值,从而实现自动分割。适用于前景和背景对比度明显的图像[^1][^2]。 - **THRESH_BINARY_INV**:这是二值化的反转模式。标准二值化(`THRESH_BINARY`)中,高于阈值的像素设为最大值(如255),低于阈值的设为0。反转模式下,高于阈值的像素设为0(黑色),低于阈值的设为最大值(白色)。公式表示为: $$ \text{binary\_inv}(x) = \begin{cases} 255 & \text{if } x < \text{threshold} \\ 0 & \text{if } x \geq \text{threshold} \end{cases} $$ - **组合 `|` 操作符**:在 OpenCV 的 `cv2.threshold` 函数中,`|` 用于结合多个标志。`THRESH_BINARY_INV | THRESH_OTSU` 表示:先使用大津法自动确定阈值,再应用二进制反转二值化。这特别适用于需要提取暗色前景(如黑色文字或物体)的应用场景[^1][^2]。 #### 2. **用法说明** 在 OpenCV 中,通过 `cv2.threshold` 函数实现此组合。函数语法如下: ```python ret, binary_image = cv2.threshold(image, 0, max_val, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) ``` - **参数解释**: - `image`:输入的灰度图像(必须是单通道)。 - `0`:阈值占位符。由于 `THRESH_OTSU` 会自动计算阈值,这设为0即可(实际阈值由算法返回)[^1][^2]。 - `max_val`:像素最大值,通常设为255(白色)。 - `cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU`:标志组合,启用自动阈值和反转二值化。 - **返回值**: - `ret`:大津法计算出的实际阈值(例如,如果图像直方图最优阈值为120,则 `ret=120`)。 - `binary_image`:输出的二值图像(反转模式)。 - **代码示例**: ```python import cv2 # 读取图像并转为灰度 image = cv2.imread('input.jpg', cv2.IMREAD_GRAYSCALE) # 应用 THRESH_BINARY_INV | THRESH_OTSU ret, binary_inv_otsu = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) # 显示结果 cv2.imshow('Binary Inverted Otsu', binary_inv_otsu) cv2.waitKey(0) cv2.destroyAllWindows() ``` **使用场景**:此组合常用于文档扫描(提取深色文字)、医学图像处理(分割暗色细胞)等,能有效处理前景比背景暗的图像[^1][^2]。 #### 3. **相关技术背景** - **大津算法(Otsu's Method)原理**: - 算法基于图像的灰度直方图,目标是最大化前景和背景的类间方差(inter-class variance)。设图像灰度级为 $L$(通常 $L=256$),像素总数为 $N$,阈值为 $t$。 - 定义前景权重 $\omega_0(t) = \sum_{i=0}^{t} p_i$,背景权重 $\omega_1(t) = \sum_{i=t+1}^{L-1} p_i$,其中 $p_i$ 是灰度级 $i$ 的概率。 - 前景均值 $\mu_0(t) = \frac{\sum_{i=0}^{t} i \cdot p_i}{\omega_0(t)}$,背景均值 $\mu_1(t) = \frac{\sum_{i=t+1}^{L-1} i \cdot p_i}{\omega_1(t)}$。 - 类间方差为 $\sigma_b^2(t) = \omega_0(t) \omega_1(t) (\mu_0(t) - \mu_1(t))^2$。 - 算法遍历所有可能的 $t$(从0到255),找到使 $\sigma_b^2(t)$ 最大的 $t$ 作为阈值: $$ t^* = \arg\max_{0 \leq t < L} \sigma_b^2(t) $$ 这确保了前景和背景的最佳分离[^1]。 - **为什么结合反转模式?**:标准 `THRESH_BINARY` 适合亮前景(如白色物体),而 `THRESH_BINARY_INV` 适合暗前景。结合大津法,能自适应处理不同光照条件的图像。 - **优点与局限**: - 优点:无需手动设置阈值,自动化程度高;计算效率高(时间复杂度 $O(L)$);适用于双峰直方图图像。 - 局限:如果图像直方图不是双峰(如均匀光照),效果可能不佳;噪声敏感时需预处理(如高斯平滑)[^1][^2]。 #### 4. **兼容性问题与注意事项** - **版本差异**:在 OpenCV 的旧版本(如 2.x)中,标志名可能为 `CV_THRESH_BINARY_INV` 和 `CV_THRESH_OTSU`,而非 `cv2.THRESH_BINARY_INV`。引用[3]提到,编译错误如 `‘CV_THRESH_BINARY_INV’ was not declared` 通常是由于版本升级导致宏定义变化。解决方案: - 使用新版本(OpenCV 3.x 或更高),推荐标志名 `cv2.THRESH_BINARY_INV`。 - 如果必须用旧版本,检查文档并替换为正确宏定义(例如,`CV_THRESH_BINARY_INV` 可能改为 `THRESH_BINARY_INV`)[^3]。 - **其他提示**: - 输入图像必须为灰度图(使用 `cv2.cvtColor` 转换彩色图)。 - 若图像对比度低,可先应用直方图均衡化。 - 大津法返回的阈值 `ret` 可用于后续分析(如目标检测)[^2]。 #### 相关问题 1. 大津算法如何计算类间方差?数学推导是什么? 2. THRESH_BINARY 和 THRESH_BINARY_INV 在实际应用中有哪些区别? 3. 如何解决 OpenCV 中阈值分割的版本兼容性问题? 4. Otsu 方法在哪些场景下可能失效?如何处理? [^1]: 深入理解 OpenCV 中的二值化:cv2.THRESH_BINARY 与 cv2.THRESH_OTSU 的组合运用。 [^2]: 在 OpenCV 中,通过在函数 cv2.threshold()中对参数 type 的类型多传递一个参数“cv2.THRESH_OTSU”,即可实现Otsu方式的阈值分割。 [^3]: error: ‘CV_THRESH_BINARY_INV’ was not declared in this scope / error: ‘CV_THRESH_OTSU’ was not ...。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值