我们这里利用openCV对图片的尺寸和质量进行压缩,来达到图片大小的压缩
下面来介绍一下,改变尺寸和质量的相关API
图像缩放
进行图像缩放的API为cv::resize
CV_EXPORTS_W void resize(InputArray src, OutputArray dst, Size dsize, double fx, double fy, int interpolation);
// src 需要进行缩放的图像数据,通常类型为cv::Mat
// dst 输出图像,通常类型为cv::Mat
// dsize 目标图像的尺寸,cv::Size类型的变量,通常为(width, height)可以设置为0
// fx 水平方向缩放因子,也就是宽的缩放,可以为0,0则表示不进行缩放
// fy 垂直方向缩放因子,也就是高的缩放,可以为0,0则表示不进行缩放
// interpolation 插值方法 默认为INTER_LINEAR
// cv::INTER_NEAREST 最近邻插值,速度最快,但质量最差
// cv::INTER_LINEAR 线性插值,速度较快,质量较好
// cv::INTER_AREA 区域插值,适用于图像缩小,速度较慢,质量最好
// cv::INTER_CUBIC 三次样条插值,速度适中,质量较好
// cv::INTER_LANCZOS4 Lanczos插值,速度适中,质量较好
通过上面的参数我们可以得知,可以利用两种方式来对图像进行缩放,第一种就是通过dsize这个参数指定目标图像的大小来进行缩放,第二种就是设置宽高的缩放因子对图像进行缩放,这两种方式互不影响,使用一种将另一种设置为0即可
图像质量
改变图像质量的API为cv::imencode
CV_EXPORTS_W bool imencode(const String& ext, InputArray img, CV_OUT std::vector<uchar>& buf, const std::vector<int>& params);
// ext 指定要使用的图像格式的文件扩展名
// img 输入的图像,通常为cv::Mat类型
// buf 输出的字节流,即编码后图像数据的存储变量
// params 可选参数用来设置编码选项,图像质量等
示例代码
通过之前讲过的Windows截图和今天说的图像压缩的API,我们来实现一个示例,就是对屏幕进行截图然后使用opencv进行图像压缩处理(尺寸缩小一半,质量降低一半),然后进行压缩前和压缩后的图像比较
代码:
int main(std::string& imageData, cv::Rect& recv) {
/// 利用CImage类实现屏幕截图
HDC hDC = GetDC(NULL);
// 在创建时,创建指定尺寸的Image
CImage image;
if (image.Create(
recv.width,
recv.height,
GetDeviceCaps(hDC, BITSPIXEL)) == FALSE)
{
TRACE("图片创建失败");
return -1;
}
// 复制指定区域的屏幕,到Image中
if (BitBlt(
image.GetDC(),
0, 0,
image.GetWidth(), image.GetHeight(),
hDC, 0, 0,
SRCCOPY) == FALSE)
{
TRACE("图片复制失败");
image.ReleaseDC();
return -2;
}
ReleaseDC(WindowFromDC(hDC), hDC);
// 创建图片数据的缓冲区
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, 0);
if (hMem == NULL) {
image.ReleaseDC();
return -3;
}
IStream* pStream = NULL;
HRESULT ret = CreateStreamOnHGlobal( // 缓冲区与输入流绑定
hMem,
TRUE,
&pStream);
if (ret != S_OK) {
TRACE("内存绑定创建失败");
GlobalFree(hMem);
image.ReleaseDC();
return -4;
}
// 保存图片到流中
image.Save(pStream, Gdiplus::ImageFormatJPEG);
image.ReleaseDC();
LARGE_INTEGER bg = {};
pStream->Seek(bg, STREAM_SEEK_SET, NULL); // 流指针移到开头
PBYTE pData = (PBYTE)GlobalLock(hMem); // 将数据锁定提取
if (pData == NULL) {
pStream->Release();
GlobalFree(hMem);
TRACE("数据大小为0\r\n");
return -5;
}
SIZE_T nSize = GlobalSize(hMem); // 获取数据大小
do {
std::string data(nSize, '\0');
memcpy((char*)data.c_str(), pData, nSize);
GlobalUnlock(hMem);
pStream->Release();
GlobalFree(hMem);
#if 1
FILE* pFile = fopen("./original.jpg", "wb+");
if (pFile == NULL) {
TRACE(_T("文件创建失败\r\n"));
return -1;
}
fwrite(data.c_str(), 1, data.size(), pFile);
fclose(pFile);
#endif
//*** 进行图片质量压缩 ***
// cv::imread() 该函数可以从磁盘中读取一张图片
cv::_InputArray src_arr((char*)data.c_str(), (int)data.size());
cv::Mat src_mat = cv::imdecode(src_arr, cv::IMREAD_COLOR);
{
std::string str;
data.swap(str);
}
if (src_mat.data == NULL) {
// 图片加载失败
TRACE("图片加载失败");
break;
}
cv::Mat amplify1;
cv::resize(src_mat, amplify1, cv::Size(), 0.5, 0.5, cv::INTER_AREA);
std::vector<uchar> pic_buff; // 保存图片的缓冲区
// 图片质量压缩
// IMWRITE_JPEG_QUALITY jpg IMWRITE_WEBP_QUALITY webp
std::vector<int> compression_params = { cv::IMWRITE_JPEG_QUALITY/*图片类型参数*/ ,50/*图片质量参数*/ }; // 图片处理参数
bool ret = cv::imencode(".jpg", amplify1, pic_buff, compression_params);
if (ret == false) {
pic_buff.clear();
break;
}
imageData.resize(pic_buff.size());
memcpy((char*)imageData.c_str(), pic_buff.data(), imageData.size());
#if 1
FILE* pFile = fopen("./dispose.jpg", "wb+");
if (pFile == NULL) {
TRACE(_T("文件创建失败\r\n"));
return -1;
}
fwrite(imageData.c_str(), 1, imageData.size(), pFile);
fclose(pFile);
#endif
cv::destroyAllWindows();
} while (false);
return 0;
}


可以看到处理后比处理前图片大小减小了75%,在网络传输中将大大减少带宽的消耗
到这里,使用openCV对图像进行压缩就介绍完了
感谢观看学习,大佬们多多指点,愿明天的自己会感谢当下的努力!!!!