1.传统的lplImage * -------> Mat格式

IplImage* img = cvLoadImage("greatwave.png", 1);

Mat mtx(img); //  IplImage* ->Mat 共享数据





2、Mat  -----> IplImage:

(1)将Mat类型转换到 IplImage *类型

Mat   image1;

IplImage  *image2 = (&(IplImage)image1);  //同样只是创建图像头,而没有复制数据。

cvsaveimage("c:\\image2.jpg",image2);//保存下来

(2)将Mat类型转换到 IplImage类型

只是创建图像头,而没有复制数据。

例:

IplImage ipl_img = img; // Mat -> IplImage

3、将CvMat类型转换为Mat类型

与IplImage的转换类似,可以选择是否复制数据。



Mat b = Mat(const CvMat* a, true);

//使用Mat的构造函数:Mat::Mat(const CvMat* m, bool copyData=false);    默认情况下copyData为false
CvMat* a;
//注意:以下三种效果一致,均为浅拷贝
Mat b(a); //a "copy" to b
Mat b(a, false); //a "copy" to b
Mat b = a; //a "copy" to b //注意:当将参数copyData设为true后,则为深拷贝(复制整个图像数据)
Mat b = Mat(a, true); //a copy to b

4、将Mat类型转换为CvMat类型

与IplImage的转换类似,不复制数据,只创建矩阵头。



例:// 假设Mat类型的imgMat图像数据存在



CvMat cvMat = imgMat; // Mat -> CvMat

//注意:浅拷贝
Mat a;
CvMat b = a; //a "copy" to b //注意:深拷贝
Mat a;
CvMat *b;
CvMat temp = a; //转化为CvMat类型,而不是复制数据
cvCopy(&temp, b); //真正复制数据 cvCopy使用前要先开辟内存空间

Mat之间的复制

//注意:浅拷贝 -  不复制数据只创建矩阵头,数据共享(更改a,b,c的任意一个都会对另外2个产生同样的作用)
Mat a;
Mat b = a; //a "copy" to b
Mat c(a); //a "copy" to c //注意:深拷贝
Mat a;
Mat b = a.clone(); //a copy to b
Mat c;
a.copyTo(c); //a copy to c

CvMat之间的复制

//注意:深拷贝 - 单独分配空间,两者相互独立
CvMat* a;
CvMat* b = cvCloneMat(a); //copy a to b

5、 (1)IplImage转Cvmat

   IplImage* src = cvLoadImage("rice.bmp",0);

   CvMat* mat=cvCreateMat(src->height,src->width,CV_32SC1);

   cvConvert(src,mat);

或者:Cvmat matObj;

   * mat=cvGetmat(src,&matObj);

  (2)Cvmat转IplImage

    IplImage*
pImg = cvCreateImage(cvGetSize(mat),8,1);   

    cvGetImage(matI,pImg);

     cvSaveImage("rice1.bmp",pImg);

4.1 IplImage与IplImage*

IplImage* imgTemp = cvCreateImage(cvSize(s_size, s_size), 8, 3);

IplImage temp = imgRGB.rowRange(rangeL, rangeR).colRange(valL, valR);

  cvResize(&temp, imgTemp);

5、CxImage 开源库与Opencv (Mat)互转

 //to
Mat
CxImage img;
img.Load("C:\\f.jpg");
uint8_t *buf=NULL;
int32_t len=0;
boolrs =img.Encode(buf,len,CXIMAGE_FORMAT_BMP);
cv::Mat temp2;
vector<uchar> buff2;
buff2.resize(len);
memcpy(&buff2[0],buf,len);
temp2= cv::imdecode(buff2,1);

delete []buf; //要释放buf,这个buf在函数里分配了内存






cv::imshow("111",temp2);
cv::waitKey();
 
//to Cximage
vector<uchar> buff;
cv::imencode(".bmp",temp2,buff);
CxImage img2(&buff[0],buff.size(),CXIMAGE_FORMAT_BMP);
img2.Blt(GetDlgItem(IDC_STATIC_P)->GetDC()->GetSafeHdc());




6、OpenCV2CXimage.h

  1. #pragma once
  2. /*
  3. * 类说明:OpenCV图像与CXimage图像互转
  4. * 用于OpenCV的图像与CXimage图像格式互转进行封装。 OpenCV的图像位数必须是大等于8的整数倍,支持BMP,JPG图像格式;CXimage的图像位数可以是1、2、4、8、、24,支持BMP,JPG,TIF,PNG,GIF图像格式。
  5. */
  6. #include <stdio.h>
  7. #include "h/ximage.h"
  8. #include <opencv2/opencv.hpp>
  9. #pragma comment(lib,"lib/cximage.lib")
  10. #pragma comment(lib,"lib/Jpeg.lib")
  11. #pragma comment(lib,"lib/libpsd.lib")
  12. #pragma comment(lib,"lib/png.lib")
  13. #pragma comment(lib,"lib/zlib.lib")
  14. #pragma comment(lib,"lib/tiff.lib")
  15. #pragma comment(lib,"lib/jasper.lib")
  16. #pragma comment(lib,"lib/libdcr.lib")
  17. #pragma comment(lib,"lib/jbig.lib")
  18. #pragma comment(lib,"lib/mng.lib")
  19. using namespace cv;
  20. using namespace std;
  21. #include <opencv2/opencv.hpp>
  22. #ifdef _DEBUG
  23. #pragma comment(lib, "opencv_core249d.lib")
  24. #pragma comment(lib, "opencv_highgui249d.lib")
  25. #pragma comment(lib, "opencv_imgproc249d.lib")
  26. #else
  27. #pragma comment(lib, "opencv_core249.lib")
  28. #pragma comment(lib, "opencv_highgui249.lib")
  29. #pragma comment(lib, "opencv_imgproc249.lib")
  30. #endif
  31. class OpenCV2CXimage
  32. {
  33. public:
  34. OpenCV2CXimage(void);
  35. ~OpenCV2CXimage(void);
  36. /*
  37. 功能说明: 获取黑点标记的方式
  38. 参数说明:  cxImage 图像处理类
  39. 返回值: 黑点标记
  40. */
  41. static int OpenCV2CXimage::GetBlackColor(CxImage cxImage);
  42. /*
  43. 功能说明: 获取白点标记的方式
  44. 参数说明:  cxImage 图像处理类
  45. 返回值: 黑点标记
  46. */
  47. static int OpenCV2CXimage::GetWhiteColor(CxImage cxImage);
  48. /*
  49. *功能说明:转换Cximage到IplImage(注:由于IplImage结构不支持图像像数非8位格式,所以强制转换成8位整数倍)
  50. *参数说明:src,表示原始Cximage图像;dst,[out] 表示Opencv图像IplImage结构
  51. *返回值:bool类型。true,表示成功;flase,表示失败。
  52. */
  53. bool Cximage2IplImage(CxImage *src,IplImage **dst);
  54. /*
  55. *功能说明:转换IplImage到Cximage
  56. *参数说明:src,表示Opencv图像IplImage结构;dst,[out] 表示输出Cximage图像;nBpp,表示输出Cximage图像位数占多少位[一个像数占多少位](1,8,24);
  57. *返回值:bool类型。true,表示成功;flase,表示失败。
  58. */
  59. bool IplImage2Cximage(IplImage *src,CxImage *dst,long nBpp=8);
  60. /*
  61. *功能说明:图象格式转换
  62. *参数说明:src,表示输入Cximage图像;dst,[out] 表示输出Cximage图像;imagetype,表示图象类型
  63. *返回值:bool类型。true,表示成功;flase,表示失败。
  64. */
  65. bool CxImageFormatConvert(CxImage *src,CxImage *dst,long imagetype = CXIMAGE_FORMAT_BMP);
  66. protected:
  67. RGBQUAD *m_pPal;//调色版
  68. int m_nPalatteCount;
  69. };

OpenCV2CXimage.cpp

  1. #include "StdAfx.h"
  2. #include "OpenCV2CXimage.h"
  3. #include <map>
  4. using namespace std;
  5. OpenCV2CXimage::OpenCV2CXimage(void)
  6. {
  7. m_pPal = NULL;
  8. m_nPalatteCount = 0;
  9. }
  10. OpenCV2CXimage::~OpenCV2CXimage(void)
  11. {
  12. if(m_pPal!=NULL)
  13. {
  14. delete []m_pPal;
  15. m_pPal = NULL;
  16. }
  17. }
  18. //函数名: GetBlackColor
  19. //功能:  获取黑点标记的方式
  20. //参数:  cxImage 图像处理类
  21. //返回值: 黑点标记
  22. int OpenCV2CXimage::GetBlackColor(CxImage cxImage)
  23. {
  24. long i;
  25. int iBlackFlag = 0;
  26. RGBQUAD *pData = cxImage.GetPalette();
  27. long nPaletteSize = cxImage.GetPaletteSize()/sizeof(RGBQUAD);
  28. for(i=0;i<nPaletteSize;i++)
  29. {
  30. if(pData[i].rgbBlue==0 && pData[i].rgbGreen==0 && pData[i].rgbRed==0)
  31. {
  32. iBlackFlag = i;
  33. break;
  34. }
  35. }
  36. return iBlackFlag;
  37. }
  38. //函数名: GetWhiteColor
  39. //功能:  获取白点标记的方式
  40. //参数:  cxImage 图像处理类
  41. //返回值: 黑点标记
  42. int OpenCV2CXimage::GetWhiteColor(CxImage cxImage)
  43. {
  44. long i;
  45. int iWhiteFlag = 255;
  46. RGBQUAD *pData = cxImage.GetPalette();
  47. long nPaletteSize = cxImage.GetPaletteSize()/sizeof(RGBQUAD);
  48. for(i=0;i<nPaletteSize;i++)
  49. {
  50. if(pData[i].rgbBlue==255 && pData[i].rgbGreen==255 && pData[i].rgbRed==255)
  51. {
  52. iWhiteFlag = i;
  53. break;
  54. }
  55. }
  56. return iWhiteFlag;
  57. }
  58. /*
  59. *功能说明:转换Cximage到IplImage
  60. *参数说明:src,表示原始Cximage图像;dst,[out] 表示Opencv图像IplImage结构
  61. *返回值:bool类型。true,表示成功;flase,表示失败。
  62. */
  63. bool OpenCV2CXimage::Cximage2IplImage(CxImage *src,IplImage **dst)
  64. {
  65. bool bRet = true;
  66. if(!src || !src->IsValid())
  67. {
  68. bRet = false;
  69. return bRet;
  70. }
  71. m_nPalatteCount = src->GetPaletteSize()/sizeof(RGBQUAD);;
  72. m_pPal = src->GetPalette();
  73. int iBackColor = GetBlackColor(*src);
  74. long i = 0,j = 0;
  75. long nImageWidth = 0,nImageHeight = 0;
  76. nImageWidth = src->GetWidth();
  77. nImageHeight = src->GetHeight();
  78. long nBitCunt = src->GetBpp();
  79. if(nBitCunt<=1)
  80. {
  81. *dst = cvCreateImage(cvSize(nImageWidth,nImageHeight),IPL_DEPTH_8U,1);
  82. cvZero(*dst);
  83. //转换Cximage to IplImage
  84. for(j=0;j<nImageHeight;j++)
  85. {
  86. for(i=0;i<nImageWidth;i++)
  87. {
  88. if(src->GetPixelIndex(i,j)==iBackColor)
  89. {
  90. CV_IMAGE_ELEM(*dst,uchar,nImageHeight-1-j,i) = 0;
  91. }
  92. else
  93. {
  94. CV_IMAGE_ELEM(*dst,uchar,nImageHeight-1-j,i) = 255;
  95. }
  96. }
  97. }
  98. }
  99. else if(nBitCunt<=8)
  100. {
  101. *dst = cvCreateImage(cvSize(nImageWidth,nImageHeight),IPL_DEPTH_8U,1);
  102. cvZero(*dst);
  103. //对应图像调色版与标准调色版的关系
  104. map<int,int> mapPalatte;
  105. RGBQUAD szSystemPal[256];
  106. int k = 0;
  107. for(k=0;k<256;k++)
  108. {
  109. szSystemPal[k].rgbBlue = k;
  110. szSystemPal[k].rgbGreen = k;
  111. szSystemPal[k].rgbRed = k;
  112. szSystemPal[k].rgbReserved = 0;
  113. }
  114. int m = 0;
  115. for(m=0;m<m_nPalatteCount;m++)
  116. {
  117. for(k=0;k<256;k++)
  118. {
  119. if(m_pPal[m].rgbBlue==szSystemPal[k].rgbBlue && m_pPal[m].rgbGreen==szSystemPal[k].rgbGreen && m_pPal[m].rgbRed==szSystemPal[k].rgbRed)
  120. {
  121. mapPalatte.insert(make_pair(m,k));
  122. break;
  123. }
  124. }
  125. }
  126. //////////////////////////////////////////////////////////////////////////
  127. //转换Cximage to IplImage
  128. map<int,int>::iterator iter;
  129. BYTE btIndex = 0;
  130. for(j=0;j<nImageHeight;j++)
  131. {
  132. for(i=0;i<nImageWidth;i++)
  133. {
  134. btIndex = src->GetPixelIndex(i,j);
  135. iter = mapPalatte.find(btIndex);
  136. if(iter!=mapPalatte.end())
  137. {
  138. btIndex = iter->second;
  139. }
  140. CV_IMAGE_ELEM(*dst,uchar,nImageHeight-1-j,i) = btIndex;
  141. }
  142. }
  143. }
  144. else if(nBitCunt<=16)
  145. {
  146. *dst = cvCreateImage(cvSize(nImageWidth,nImageHeight),IPL_DEPTH_16U,1);
  147. (*dst)->origin = 1;//底—左结构 (Windows bitmaps 风格)
  148. cvZero(*dst);
  149. //转换Cximage to IplImage
  150. for(j=0;j<nImageHeight;j++)
  151. {
  152. for(i=0;i<nImageWidth;i++)
  153. {
  154. BYTE *pSrc = src->GetBits(j) + 2*i;
  155. CV_IMAGE_ELEM(*dst,ushort,j,i) = (*pSrc) + (*(pSrc+1))*256;
  156. }
  157. }
  158. }
  159. else //24色
  160. {
  161. *dst = cvCreateImage(cvSize(nImageWidth,nImageHeight),IPL_DEPTH_8U,3);
  162. (*dst)->origin = 1;//底—左结构 (Windows bitmaps 风格)
  163. cvZero(*dst);
  164. //转换Cximage to IplImag
  165. memcpy((*dst)->imageData,src->GetBits(0),src->GetSize());
  166. }
  167. return bRet;
  168. }
  169. /*
  170. *功能说明:转换IplImage到Cximage
  171. *参数说明:src,表示Opencv图像IplImage结构;dst,[out] 表示输出Cximage图像;nBpp,表示输出Cximage图像位数占多少位[一个像数占多少位]
  172. *返回值:bool类型。true,表示成功;flase,表示失败。
  173. */
  174. bool OpenCV2CXimage::IplImage2Cximage(IplImage *src,CxImage *dst,long nBpp)
  175. {
  176. bool bRet = true;
  177. if(src==NULL || dst==NULL)
  178. {
  179. return false;
  180. }
  181. if(!(nBpp==1 || nBpp==8 || nBpp==24))
  182. {
  183. return false;
  184. }
  185. long i = 0,j = 0;
  186. CvSize csImageSize = cvGetSize(src);
  187. CxImage ciTmp;
  188. ciTmp.Create(csImageSize.width,csImageSize.height,src->depth,CXIMAGE_FORMAT_BMP);
  189. if(src->depth== IPL_DEPTH_8U)//灰度
  190. {
  191. ciTmp.SetStdPalette();
  192. BYTE gray = 0;
  193. for(j=0;j<csImageSize.height;j++)
  194. {
  195. for(i=0;i<csImageSize.width;i++)
  196. {
  197. gray = CV_IMAGE_ELEM(src,uchar,csImageSize.height-1-j,i);
  198. COLORREF color = 0;
  199. color |= gray;
  200. color |= gray << 8;
  201. color |= gray << 16;
  202. ciTmp.SetPixelColor(i,j,color);
  203. }
  204. }
  205. }
  206. else //彩色
  207. {
  208. //转换IplImag to Cximage
  209. memcpy(ciTmp.GetBits(0),src->imageData,src->imageSize);
  210. }
  211. //转换成需要的目标图像
  212. dst->Create(csImageSize.width,csImageSize.height,nBpp,CXIMAGE_FORMAT_BMP);
  213. if(nBpp==ciTmp.GetBpp())
  214. {
  215. dst->Copy(ciTmp);
  216. dst->Save("dst.bmp",CXIMAGE_FORMAT_BMP);
  217. }
  218. else
  219. {
  220. if(nBpp==1)//二值
  221. {
  222. //对应图像调色版与标准调色版的关系
  223. map<int,int> mapPalatte;
  224. RGBQUAD szSystemPal[256];
  225. int k = 0;
  226. for(k=0;k<256;k++)
  227. {
  228. szSystemPal[k].rgbBlue = k;
  229. szSystemPal[k].rgbGreen = k;
  230. szSystemPal[k].rgbRed = k;
  231. szSystemPal[k].rgbReserved = 0;
  232. }
  233. int m = 0;
  234. for(k=0;k<256;k++)
  235. {
  236. for(m=0;m<m_nPalatteCount;m++)
  237. {
  238. if(m_pPal[m].rgbBlue==szSystemPal[k].rgbBlue && m_pPal[m].rgbGreen==szSystemPal[k].rgbGreen && m_pPal[m].rgbRed==szSystemPal[k].rgbRed)
  239. {
  240. mapPalatte.insert(make_pair(k,m));
  241. break;
  242. }
  243. }
  244. }
  245. //////////////////////////////////////////////////////////////////////////
  246. byte btValue = 0;
  247. map<int,int>::iterator iter;
  248. long nImageWidth = 0;
  249. long nImageHeight = 0;
  250. if(ciTmp.GetBpp()>8)
  251. {
  252. ciTmp.GrayScale();
  253. }
  254. if(m_nPalatteCount==2) //表示原始的图象为二值图象
  255. {
  256. dst->SetPalette(m_pPal,m_nPalatteCount);
  257. btValue = 0;
  258. nImageWidth = ciTmp.GetWidth();
  259. nImageHeight = ciTmp.GetHeight();
  260. for(j=0;j<nImageHeight;j++)
  261. {
  262. for(i=0;i<nImageWidth;i++)
  263. {
  264. btValue = ciTmp.GetPixelIndex(i,j);
  265. iter = mapPalatte.find(btValue);
  266. if(iter!=mapPalatte.end())
  267. {
  268. btValue = iter->second;
  269. }
  270. dst->SetPixelIndex(i,j,btValue);
  271. }
  272. }
  273. }
  274. else
  275. {
  276. ciTmp.Threshold(128);
  277. dst->Copy(ciTmp);
  278. }
  279. }
  280. else if(nBpp==8)
  281. {
  282. //对应图像调色版与标准调色版的关系
  283. map<int,int> mapPalatte;
  284. RGBQUAD szSystemPal[256];
  285. int k = 0;
  286. for(k=0;k<256;k++)
  287. {
  288. szSystemPal[k].rgbBlue = k;
  289. szSystemPal[k].rgbGreen = k;
  290. szSystemPal[k].rgbRed = k;
  291. szSystemPal[k].rgbReserved = 0;
  292. }
  293. int m = 0;
  294. for(k=0;k<256;k++)
  295. {
  296. for(m=0;m<m_nPalatteCount;m++)
  297. {
  298. if(m_pPal[m].rgbBlue==szSystemPal[k].rgbBlue && m_pPal[m].rgbGreen==szSystemPal[k].rgbGreen && m_pPal[m].rgbRed==szSystemPal[k].rgbRed)
  299. {
  300. mapPalatte.insert(make_pair(k,m));
  301. break;
  302. }
  303. }
  304. }
  305. //////////////////////////////////////////////////////////////////////////
  306. byte btValue = 0;
  307. map<int,int>::iterator iter;
  308. long nImageWidth = 0;
  309. long nImageHeight = 0;
  310. if(ciTmp.GetBpp()!=8)
  311. {
  312. ciTmp.GrayScale();
  313. }
  314. if(m_nPalatteCount==8) //表示原始的图象为灰度图象
  315. {
  316. dst->SetPalette(m_pPal,m_nPalatteCount);
  317. btValue = 0;
  318. nImageWidth = ciTmp.GetWidth();
  319. nImageHeight = ciTmp.GetHeight();
  320. for(j=0;j<nImageHeight;j++)
  321. {
  322. for(i=0;i<nImageWidth;i++)
  323. {
  324. btValue = ciTmp.GetPixelIndex(i,j);
  325. iter = mapPalatte.find(btValue);
  326. if(iter!=mapPalatte.end())
  327. {
  328. btValue = iter->second;
  329. }
  330. dst->SetPixelIndex(i,j,btValue);
  331. }
  332. }
  333. }
  334. else
  335. {
  336. dst->Copy(ciTmp);
  337. }
  338. }
  339. else
  340. {
  341. if(ciTmp.GetBpp()==24)
  342. {
  343. dst->Copy(ciTmp);
  344. }
  345. else
  346. {
  347. byte btValue = 0;
  348. COLORREF clValue;
  349. map<int,int>::iterator iter;
  350. long nImageWidth = 0;
  351. long nImageHeight = 0;
  352. bRet = ciTmp.IncreaseBpp(24);
  353. dst->Copy(ciTmp);
  354. }
  355. }
  356. }
  357. return bRet;
  358. }
  359. //图象格式转换
  360. bool OpenCV2CXimage::CxImageFormatConvert(CxImage *src,CxImage *dst,long imagetype)
  361. {
  362. bool bRet = true;
  363. if(src==NULL || dst==NULL)
  364. {
  365. return false;
  366. }
  367. if(!(imagetype>0 && imagetype<=19))
  368. {
  369. return false;
  370. }
  371. if(src->GetType()==imagetype)
  372. {
  373. dst->Copy(*src);
  374. }
  375. else
  376. {
  377. dst->Create(src->GetWidth(),src->GetHeight(),src->GetBpp(),imagetype);
  378. src->SetType(imagetype);
  379. dst->Copy(*src);
  380. }
  381. return true;
  382. }

main函数:

  1. // OpencvtoCximg.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include "OpenCV2CXimage.h"
  5. int _tmain(int argc, _TCHAR* argv[])
  6. {
  7. //  cvNamedWindow("img",CV_WINDOW_AUTOSIZE);
  8. //Cximage--->IplImage
  9. IplImage *img;
  10. OpenCV2CXimage o2i;
  11. CxImage cimg("gimg.bmp",CXIMAGE_FORMAT_BMP);
  12. CxImage *cimg1 = new CxImage();
  13. cimg1->Load("gimg.bmp",CXIMAGE_FORMAT_BMP);
  14. o2i.Cximage2IplImage(cimg1 ,&img);
  15. cvSaveImage("img.jpg",img);
  16. //cvShowImage("img",img);
  17. //cvWaitKey(0);
  18. //IplImage-->Cximage
  1. CxImage *cimg2 = new CxImage();
  2. IplImage *img1;
  3. img1=cvLoadImage("gimg.bmp",0);
  4. o2i.IplImage2Cximage(img1,cimg2,8);
  5. cimg2->Save("test2.bmp",CXIMAGE_FORMAT_BMP);
  6. //CxImage合并图片
  7. CxImage im1,im2,im3;
  8. int h1,w1,h2,w2,h3,w3,bpp;
  9. im1.Load("E:\\2.jpg");
  10. im2.Load("E:\\1.jpg");
  11. h1=im1.GetHeight();
  12. w1=im1.GetWidth();
  13. h2=im2.GetHeight();
  14. w2=im2.GetWidth();
  15. h3=h1;
  16. w3=w1+w2;
  17. bpp=im1.GetBpp();
  18. im3.Create(w3,h3,bpp);
  19. im3.MixFrom(im1,0,0);
  20. im3.MixFrom(im2,w1,0);
  21. im3.Save("e:\\3.jpg",CXIMAGE_FORMAT_JPG);
  22. //用CxImage给图片加上文字水印
  23. CxImage imagesy;
  24. if( !imagesy.Load("E:\\1.jpg", CXIMAGE_FORMAT_JPG))
  25. {
  26. return TRUE;
  27. }
  28. if (imagesy.IsValid())
  29. {
  30. CxImage::CXTEXTINFO  textword;
  31. imagesy.InitTextInfo( &textword );
  32. _stprintf( textword.lfont.lfFaceName,  _T("Times New Roman"));
  33. textword.lfont.lfCharSet   =  GB2312_CHARSET  ;
  34. textword.lfont.lfWeight    =  8 ;
  35. textword.lfont.lfItalic    =  0 ;
  36. textword.lfont.lfUnderline =  0 ;
  37. textword.fcolor =  RGB( 255,255,160 );
  38. textword.bcolor = RGB(   0, 80,160 );
  39. textword.opaque =  1; //背景
  40. textword.b_opacity = (float)(0)/(float)200.;  //透明度
  41. textword.b_round   = (BYTE) 10 ; //四舍五入为背景矩形半径
  42. textword.smooth    = (BYTE)1;  //平滑选项的文本
  43. _stprintf( textword.text, _T("水印文字") );
  44. imagesy.DrawStringEx(0,0,100,&textword);
  45. imagesy.Save("e:\\z2_sy.jpg",CXIMAGE_FORMAT_JPG);
  46. }
  47. return 0;

一.Mat基础(如果加了using namespace cv ,以下的cv:: 都可以省略)

在计算机内存中,数字图像是已矩阵的形式保存的。OpenCV2中,数据结构Mat是保存图像像素信息的矩阵,它主要包含两部分:矩阵头和一个指向像素数据的矩阵指针。
矩阵头主要包含,矩阵尺寸、存储方法、存储地址和引用次数等。
矩阵头的大小是一个常数,不会随着图像的大小而改变,但是保存图像像素数据的矩阵则会随着图像的大小而改变,通常数据量会很大,比矩阵头大几个数量级。这样,在图像复制和传递过程中,主要的开销是由存放图像像素的矩阵而引起的。因此,OpenCV使用了引用次数,当进行图像复制和传递时,不再复制整个Mat数据,而只是复制矩阵头和指向像素矩阵的指针。例如:

cv::Mat a ;//创建矩阵头
a = cv::imread("f:\\psb.jpg");//读入图像
cv::Mat b = a ;//复制 
上面的a,b有各自的矩阵头,但是其矩阵指针指向同一个矩阵,也就是其中任何一个改变了矩阵数据都会影响另外一个。
那么,多个Mat共用一个矩阵数据,最后谁来释放矩阵数据呢?
这就是引用计数的作用,当Mat对象每被复制一次时,就会将引用计数加1,而每销毁一个Mat对象(共用同一个矩阵数据)时引用计数会被减1,当引用计数为0时,矩阵数据会被清理。
上图是Mat对象a,b共用一个矩阵,故其引用计数refcount为2.
但是有些时候仍然会需要复制矩阵数据本身(不只是矩阵头和矩阵指针),这时候可以使用clone 和copyTo方法。
cv::Mat c = a.clone();
cv::Mat d ;
a.copyTo(d);
上面代码中的c,d各自拥有自己的矩阵,改变自己的矩阵数据不会相互影响。
在使用Mat中,需要记住:
  1. OpenCV中的内存分配是自动完成的(不是特别指定的话)
  2. 使用OpenCV的C++ 接口时不需要考虑内存释放问题
  3. Mat的赋值运算和拷贝构造函数只会拷贝矩阵头,仍然共同同一个矩阵
  4. 如果要复制矩阵数据,可以使用clone和copyTo函数

2.Mat存储方法

Mat中矩阵的每个元素可以使用不同的数据类型,最小的数据类型是char,占用一个字节或者8位,可以是有符号的(0到255)或者是无符号的(-127到127)。在RGB颜色空间中,使用三个char类型可以表示1600万中颜色,但在图像处理的过程中有可能会使用到float或者double来表示图像的像素。

Mat的创建

构造函数
cv::Mat img(2,2,CV_8UC3,cv::Scalar(0,0,255));
上述代码创建了一个2行2列的矩阵,矩阵元素使用8位无符号char类型保存,具有3通道,每个像素的初始值是(0,0,255)

构造函数的前两个参数指定了矩阵的行和列

第三个参数指定矩阵元素的数据类型以及通道数,
四部分分别指定:元素的大小,是有符号还是无符号,数据类型以及通道数
最后一个参数,Scalar是short型的vector,提供矩阵的初始化。
Create方法
该方法不能为矩阵设置初始值,只是在改变尺寸时为矩阵数据重新分配内存。使用方法:
img.create(4,4,CV_8UC(2));
创建了一个4行4列有2个通道的矩阵
 
MATLAB形式的初始化
cv::Mat e = cv::Mat::eye(4,4,CV_64F);
cv::Mat z = cv::Mat::ones(2,2,CV_32F);
cv::Mat o = cv::Mat::zeros(3,3,CV_8UC1);
Mat e是4行4列的对角矩阵
Mat z是2行2列的单位矩阵
Mat o是3行3列的零矩阵
小矩阵的初始化
对于小矩阵可以使用逗号分割的初始化函数
Mat c =(Mat_<double>(3,3)<<1,2,3,0,-1,0,4,5,6);

3.Mat的输入输出

使用imread函数,向Mat对象中写入一个图像。
a = cv::imread("f:\\psb.jpg");//读入图像
imread的原型如下
cv::Mat imread(const string& filename,int flags=1)

filename指定要读取图像的位置

flags指定图像的颜色空间  
    flags > 0     3通道的彩色图像
    flags = 0     灰度图像
    flags < 0     不作改变
也可以有以下的枚举值
CV_LOAD_IMAGE_ANYDEPTH、CV_LOAD_IMAGE_COLOR、CV_LOAD_IMAGE_GRAYSCALE
 
使用imwrite函数,将Mat对象保存到指定的文件中。
imwrite的函数原型如下:
bool imwrite(const string& filename,InputArray img,constvector<int>& params=vector<int>())
filename,指定的文件
img  要保存的Mat对象
params 用来指定图像的保存编码方式。
使用filename的扩展名来指定图像的保存格式(.jpg  .png  .bmp),对于不同的图像保存类型,params是不同的值
  • JPEG,params用来指定图像的质量(0到100),默认的是95.  CV_IMWRITE_JPEG_QUALITY
  • PNG,params用来指定图像的压缩级别(0到9),压缩级别越高图像占用的空间越小,保存图像所用的时间越久。默认值是3. CV_IMWRITE_PNG_COMPRESSION
  • PPM,PGM,PBM,params是一个标记(0或者1),默认的是1.CV_IMWRITE_PXM_BINARY
imwrite只能保存8位(或者是16位无符号(CV_16UC)的PNG,JPEG200或者TIFF图像)单通道或者三通道的图像,如果要保存的不是这样的图片,可以使用convertTo或者cvtColor来进行转变。
下面代码展示了如果使用imwrite向文件中写入一个4通道的png图像
  1. #include <iostream>
  2. #include <opencv2/core/core.hpp>
  3. #include <opencv2/highgui/highgui.hpp>
  4. using namespace std;
  5. using namespace cv;
  6. Mat src;
  7. Mat image;
  8. string str = "./";
  9. /*创建alpha表,整体偏红色,左上角到右下角呈现从完全透明到完全不透明变化趋势*/
  10. void createAlphaMat(Mat &mat)
  11. {
  12. for (int i = 0; i < mat.rows; ++i) {
  13. for (int j = 0; j < mat.cols; ++j) {
  14. Vec4b& rgba = mat.at<Vec4b>(i, j);
  15. rgba[0] = UCHAR_MAX;    //r分量一直最大,所以整体偏红
  16. rgba[1] = saturate_cast<uchar>((float (mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX);
  17. rgba[2] = saturate_cast<uchar>((float (mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX);
  18. rgba[3] = saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2]));
  19. }
  20. }
  21. }
  22. int main()
  23. {
  24. /*采用默认参数进行图片的保存*/
  25. src = imread("test.jpg");
  26. imwrite(str+"原图.jpg", src); //c版本中的保存图片为cvSaveImage()函数,c++版本中直接与matlab的相似,imwrite()函数。
  27. imshow("src", src);
  28. Rect rect(src.cols/4, src.rows/4, src.cols/2, src.rows/2);
  29. image = src(rect);
  30. imwrite(str+"截取原图中的一部分区域小图.jpg", image);
  31. imshow("image", image);
  32. /*采用自己设置的参数来保存图片*/
  33. Mat mat(480, 640, CV_8UC4);
  34. createAlphaMat(mat);
  35. vector<int> compression_params;
  36. compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
  37. compression_params.push_back(9);    //png格式下,默认的参数为3.
  38. try {
  39. imwrite("alpha.png", mat, compression_params);
  40. }
  41. catch (runtime_error& ex) {
  42. fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what());
  43. return 1;
  44. }
  45. fprintf(stdout, "Saved PNG file with alpha data.\n");
  46. waitKey(0);
  47. return 0;
  48. }

生成的alpha表图像显示如下:

  

4.Mat的显示

OpenCV提供了用以窗口的形式显示图片的方法,代码如下:

  1. Mat img = imread("f:\psb.jpg");
  2. const string name ="Hu";
  3. namedWindow(name);
  4. imshow(name,img);
  5. waitKey();

Mat矩阵中数据元素的地址计算公式:

addr(Mi0,i1,…im-1) = M.data + M.step[0] * i0 + M.step[1] * i1 + … + M.step[m-1] * im-1 。

其中 m = M.dims 是指M的维度

i. data:Mat对象中的一个指针,指向内存中存放矩阵数据的一块内存 (uchar* data).

ii. row: 行;col:列;rows:行数;cols:列数。

iii. dims :Mat所代表的矩阵的维度,如 3 * 4 的矩阵为 2 维,3 * 4 * 5 的为3维.

iv. channels:通道,矩阵中的每一个矩阵元素拥有的值的个数,比如说 3 * 4 矩阵中一共 12 个元素,如果每个元素有三个值,那么就说这个矩阵是 3 通道的,即 channels = 3。常见的是一张彩色图片有红、绿、蓝三个通道。但是opencv用imread(opencv读图的函数)读进来的图像,三通道存放顺序为B、G、R。

v. depth:深度,即每一个像素的位数(bits),在opencv的Mat.depth()中得到的是一个 0 – 6 的数字,分别代表不同的位数:enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }; 可见 0和1都代表8位, 2和3都代表16位,4和5代表32位,6代表64位;

vi. step:是一个数组,定义了矩阵的布局,具体见下面图片分析,另外注意 step1 (step / elemSize1),M.step[m-1] 总是等于 elemSize,M.step1(i)返回的是第i维的步长,因此M.step1(m-1)总是等于 channels,m是M的维度;这里是解释步长step[k]的,步长也可以看作是与第k维的存储单位,在2维的矩阵中,因为存储是按照行的顺序存储的,整个矩阵存储为一个平面,所以第k=0维的步长也就是单位肯定就是一行所占的字节数;如果是3维的话,第0维是按照面为单位来存储的,第1维是按照行为单位来存储的,第2维是按照元素类型为单位存储的,每个元素类型是基本类型(即uchar,float,short等等)与通道数的乘积...;也就是基本数据类型与通道数组成元素,多个元素组成了行,多行组成了面,多个面组成了3维体,多个3维体 组成4维超体。。。以此类推,如此看来某一维的步长应该等于高一维的步长step*低一维的大小size 。

vii. elemSize : 矩阵中每一个元素的数据大小,如果是n通道,就是(n*数据类型)。如果Mat中的数据的数据类型是 CV_8U 那么 elemSize = 1,CV_8UC3 那么 elemSize = 3,CV_16UC2 那么 elemSize = 4;记住另外有个 elemSize1 表示的是矩阵中数据类型的大小,即 elemSize / channels 的大小。

像素位深度是指每个像素所用的位数(bit),像素位深度决定了彩色图像的每个像素可能有的颜色数,或者确定灰度图像的每个像素可能有的灰度级数。例如,一幅彩色图像的每个像素用R、G、B三个分量来表示,若每个分量用8位,那么一个像素共用24位表示,就说像素的深度为24位,每个像素可以是224,即16777216〔千万级〕种颜色中的一种。在这个意义上, 往往把像素的位深度说成是图像深度。表示一个像素的位数越多,它能表达的颜色数目就越多, 而它的深度就越深。虽然像素位深度或图像深度可以很深,但由于设备本身的限制,加上人眼自身分辨率的局限,一般情况下,一味追求特别深的像素深度没有意义。因为,像素深度越深,数据量越大,所需要的传输带宽及存储空间就越大。相反,如果像素深度太浅,会影响图像的质量,图像看起来让人觉得很粗糙而不自然。

提示:假如像素位深度是8(bit),那么以虚线框中4个像素点而言,以4 :2:0格式为例,釆样总共为6个采样点(4个亮度分量加2个色度分量),总共需要6×8=48比特,平均每个像素48/4=12比特,这就是为什么有些情况下4 :2:0采样格式也被称为“12比特每像素采样”的原因。

【视频开发】CximageMat 、CximagelplImage 以及 lplImageMat的转换、像素位深度的更多相关文章

  1. 浅谈iOS视频开发

     浅谈iOS视频开发 这段时间对视频开发进行了一些了解,在这里和大家分享一下我自己觉得学习步骤和资料,希望对那些对视频感兴趣的朋友有些帮助. 一.iOS系统自带播放器 要了解iOS视频开发,首先我们从 ...

  2. iOS 视频开发学习

    原文:浅谈iOS视频开发 这段时间对视频开发进行了一些了解,在这里和大家分享一下我自己觉得学习步骤和资料,希望对那些对视频感兴趣的朋友有些帮助. 一.iOS系统自带播放器 要了解iOS视频开发,首先我 ...

  3. Android IOS WebRTC 音视频开发总结(八十三)-- 使用WebRTC广播网络摄像头视频(上)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  4. Android 音视频开发学习思路

    Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...

  5. Android开发 音视频开发需要了解的专业术语知识

    前言 在摸索一段时间的音视频开发后,越来越发现这个坑的深度真是特别的深. 除了了解Android自带的音视频处理API以外,还得了解一些视频与音频方面的知识.这篇博客就是主要讲解这方面的专业术语.内容 ...

  6. 音视频开发-FFmpeg

    音视频开发是个非常复杂的,庞大的开发话题,初涉其中,先看一下结合 OEIP(开源项目) 新增例子. 可以打开flv,mp4类型文件,以及rtmp协议音视频数据,声音的播放使用SDL. 把采集的麦/声卡 ...

  7. Python音视频开发:消除抖音短视频Logo和去电视台标

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...

  8. Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...

  9. moviepy音视频开发:音频剪辑基类AudioClip

    ☞ ░ 前往老猿Python博文目录 ░ 一.背景知识介绍 1.1.声音三要素: 音调:人耳对声音高低的感觉称为音调(也叫音频).音调主要与声波的频率有关.声波的频率高,则音调也高. 音量:也就是响度 ...

随机推荐

  1. postgres —— 窗口函数入门

    注:测试数据在 postgres —— 分组集与部分聚集 中 聚集将多行转变成较少.聚集的行.而窗口则不同,它把当前行与分组中的所有行对比,并且返回的行数没有变化. 组合当前行与 production ...

  2. ZOJ - 3265: Strange Game (优化 二分图匹配)

    pro:有一个长度为N的数组a[i],要求选择k[i]>0,使得b[i]=a[i]^k[i]%M中出现的不同数最多.N<=200, M<=1e9: sol:a^x%p的个数的有限的, ...

  3. git version info & svn version info map(七)

    To generate the same version number as SVN, we can generate the same version number as SVN with the ...

  4. 关于windbg报错"No symbols for ntdll. Cannot continue."问题

    最近我写个例子程序研究下某个异常情况,故意制造了个崩溃.然后分析dmp文件. 当我执行!address -summary命令想观察下进程当前内存情况时,去报如下错误: 0:000> !addre ...

  5. NTSTATUS代码摘录

    00000000 STATUS_SUCCESS00000000 STATUS_WAIT_000000001 STATUS_WAIT_100000002 STATUS_WAIT_200000003 ST ...

  6. Comet OJ 2019 夏季欢乐赛题解

    Comet OJ 2019 夏季欢乐赛题解 我是来骗访问量的 A 完全k叉树 \(n\)个点的完全k叉树的直径. 直接做 B 距离产生美 直接做 C 烤面包片 \(n!!!\mod p\) 显然\(n ...

  7. 羊村的OI题解

    目录 喜羊羊与灰太狼--仓库管理 喜羊羊与灰太狼--破译密码 喜羊羊与灰太狼--烦恼的礼物 喜羊羊与灰太狼--仓库管理 传送门 水的一批,还让开o2了 就不写了 #include<iostrea ...

  8. P1270 “访问”美术馆——不太一样的树形DP

    P1270 “访问”美术馆 dfs读入,存图有点像线段树: 在枚举时间时,要减去走这条边的代价: #include<cstdio> #include<cstring> #inc ...

  9. Echarts 入门操作

    Echarts具有丰富的图表,可以说是数据可视化的神器: 1.下载Echarts 到官网或者点击以下文字[下载Echarts]即可下载: ①官网下载地址:https://echarts.baidu.c ...

  10. VS2019(NET Core 3.0)发布单文件可执行程序

    NET Core 3.0 发布单文件可执行程序 两种方法. 一.右击vs编辑项目文件,增加PublishSingleFile节点配置,代码如下: <Project Sdk="Micro ...