生成图像缩略图有以下几个步骤:
- 1.读取图像
- 2.按照预期的缩略图大小,缩小图像
- 3.保存或显示到相关控件
经过在网上多方查找并亲自测试,总结出以下两种方法,并显示到ListControl控件
缩略图最终存放在CImageList的变量里,具体步骤如下
- 1. 申明变量,并与控件绑定
- 2. 根据需要设置list控件,确定每行中各列的表头及其宽度
- 3. 生成缩略图列表
- 4. 将CListControl与CImageList绑定
直接上代码吧
#define THUMBNAIL_WIDTH 100
#define THUMBNAIL_HEIGHT 75
CImageList m_thumbnailList; // 缩略图列表
CListCtrl m_listImgFile; // 列表控件,已与具体控件绑定
// Image List -- list control init
CRect rect;
m_listImgFile.GetClientRect(&rect);
int iLength = rect.Width();
m_listImgFile.SetExtendedStyle(m_listImgFile.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
m_listImgFile.InsertColumn(0, _T("图像ID"), LVCFMT_CENTER, iLength / 3);
m_listImgFile.InsertColumn(2, _T("文件"), LVCFMT_CENTER, iLength / 3);
m_listImgFile.InsertColumn(3, _T("宽度"), LVCFMT_CENTER, iLength / 6);
m_listImgFile.InsertColumn(4, _T("高度"), LVCFMT_CENTER, iLength / 6);
m_thumbnailList.Create(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, ILC_MASK|ILC_COLOR32, 0, 0); // 生成缩略图列表
m_listImgFile.SetImageList(&m_thumbnailList, LVSIL_SMALL); // 将CImageList与List Control绑定
以下是生成缩略图的方法,因为list控件只接受CBitmap*的图像变量,所以无论哪种方法,最后都需要把图像转换成CBitmap*的格式。
前提条件:对于OpenCV3.0以后的版本,需要2.0版本里的两个文件CvvImage.h和CvvImage.cpp,用来将Mat格式转换成CBitmap格式。当然如果对CBitmap和Mat结构很了解,也可以直接硬转。
先上转换函数
CBitmap* MatToCBitmap(Mat img)
{
CDC dc;
CDC memDC;
if (!dc.CreateDC(_T("DISPLAY"), NULL, NULL, NULL))
return NULL;
if (!memDC.CreateCompatibleDC(&dc))
return NULL;
CBitmap *bmp = new CBitmap();
CBitmap* pOldBitmap;
bmp->CreateCompatibleBitmap(&dc, img.cols, img.rows);
pOldBitmap = memDC.SelectObject(bmp);
CvvImage cvImage; // you will need OpenCV_2.2.0- to use CvvImage
cvImage.CopyOf(&IplImage(img));
cvImage.Show(memDC.m_hDC, 0, 0, img.cols, img.rows, 0, 0);
cvImage.Destroy();
memDC.SelectObject(pOldBitmap);
memDC.DeleteDC();
dc.DeleteDC();
return bmp;
}
从这个函数里可以看出来,实际的转换过程就是把Mat转换给CvvImage,然后申请一块内存,CvvImage把图像显示到这块内存中,然后返回这块内存的图像句柄。
这里有个隐患,bmp这个变量是new出来的,但是最后没有释放,可能会引起内存泄漏
先上代码:
String fileName;
Mat m_img;
Mat cvimg = imread(fileName, 1);
resize(cvimg, m_img, cv::Size(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT), .0, .0, CV_INTER_AREA);
CBitmap* bmpImg = MatToCBitmap(m_img);
//m_thumbnailList.Add(bmpImg, COLORREF(0));
m_thumbnailList.Replace(i, bmpImg, NULL);
// 给List Control添加数据
CString tmp;
tmp.Format(_T("%d"), i+1);
m_listImgFile.InsertItem(i, tmp, i);
m_listImgFile.SetItemText(i, 1, imgName);
tmp.Format(_T("%d"), cvimg.cols);
m_listImgFile.SetItemText(i, 2, tmp);
tmp.Format(_T("%d"), cvimg.rows);
m_listImgFile.SetItemText(i, 3, tmp);
delete bmpImg;
bmpImg = NULL;
生成比较简单,直接resize就可以了,插值方法用CV_INTER_AREA,一般opencv缩放时,放大的插值用CV_INTER_LINEAR,缩小的插值用CV_INTER_AREA。
代码中的变量i,是图像的序号,因为我打开了多个图像文件。
最后delete bmpImg,是为了防止MatToCBitmap中的内存泄漏。
前提条件:需要引用gdiplus.h,同时还要对gdiplus初始化,用完后要释放
#include
using namespace Gdiplus;
ULONG_PTR m_gdiplusToken;
// initialize GDI+
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
释放gdiplus
// release GDI+ resource
GdiplusShutdown(m_gdiplusToken);
生成缩略图并显示
String fileName;
Mat m_img;
Matcv img = imread(fileName, 1);
Bitmap img(fileName);
Bitmap* pThumbnail = static_cast(img.GetThumbnailImage(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, NULL, NULL));
// attach the thumbnail bitmap handle to an CBitmap object
pThumbnail->GetHBITMAP(NULL, &hBmp);
pImage = new CBitmap();
pImage->Attach(hBmp);
// add bitmap to our image list
m_thumbnailList.Replace(i, pImage, NULL);
// 给List Control添加数据
CString tmp;
tmp.Format(_T("%d"), i+1);
m_listImgFile.InsertItem(i, tmp, i);
m_listImgFile.SetItemText(i, 1, imgName);
tmp.Format(_T("%d"), cvimg.cols);
m_listImgFile.SetItemText(i, 2, tmp);
tmp.Format(_T("%d"), cvimg.rows);
m_listImgFile.SetItemText(i, 3, tmp);
delete pImage;
delete pThumbnail;
显示部分两种方法都一样。在最开始的时候我用opencv读取了文件,目的是为了得到图像的长宽。
有两件事情需要说明一下
- 1.给CImageList中增加图像
有两种方法,Add(…)和Replace(…)
(1)m_thumbnailList.Add(bmpImg, COLORREF(0));
(2)m_thumbnailList.Replace(i, bmpImg, NULL);
我自己测试后发现Add函数需要一个模板COLORREF,加了这个模板缩略图变成全黑,由于时间关系,我没有深入研究直接采用了第(2)个方法。
要是有童鞋有解决方法,能共享一下最好…………