以下方法中只有方法二为.NET调用,其它均为C++程序实现。
方法一:
利用OpenCV库中的imwrite函数或者cvSaveImage函数实现。
(1) Imwrite
vector<int>CompressionPara;
CompressionPara.push_back(CV_IMWRITE_PNG_COMPRESSION);
CompressionPara.push_back(9); //参数越大,压缩比例越高
imwrite(pic1, SaveImgFront, CompressionPara);
(2) cvSaveImage
int CompressionParams[3];
CompressionParams[0]= CV_IMWRITE_PNG_COMPRESSION;
CompressionParams[1]= 9;
cvSaveImage(saveSubName.c_str(), img, CompressionParams);
以上代码段重点在于函数的第3个输入参数,该参数用于调整压缩比例。
优点:代码易于管理,压缩比率可调整,不需要保存图片后再压缩,时间短。无损压缩。
缺点:压缩比例小,压缩后图片大概缩小为原图的90%左右。
方法二:
在C#端调用第三方压缩软件pngquant.exe,进行图片压缩。
string exepath = @"C:\Users\yf\Desktop\pngquant\pngquant.exe";
string path = @"C:\Users\yf\Desktop\pngquant\pic\";
DirectoryInfo dir = new DirectoryInfo(path);
FileInfo[] inf = dir.GetFiles();
foreach(FileInfo finf in inf)
{
if (finf.Extension.Equals(".png"))
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName= exepath;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute= false;
process.StartInfo.Arguments= " pngquant -f --ext .png --quality 20-50--speed 3 " + "\"" + dir.ToString() + finf.ToString() + "\"";
process.Start();
process.WaitForExit();
}
}
以上代码段重点在于调用exe时的传入参数,该参数指定了图片压缩后的质量(--quality)、压缩速度(--speed)、生成图片的扩展名(--ext)及需要处理的图片路径(“PATH”)。该软件压缩后的图片的位深度随着压缩质量和速度参数的变化而变化。
优点:压缩比率及速度均可以调整,较为灵活;参数适中时图片压缩的质量较好。
缺点:需要在客户端实现,不能融合进dll;图片需先生成在处理,耗时长。
方法三:
利用CxImage库进行图像压缩。
CxImage dst;
dst.Create(src1.size().width, src1.size().height, 8, CXIMAGE_FORMAT_BMP);
dst.SetXDPI(133);
dst.SetYDPI(133);
dst.SetStdPalette();
long i = 0, j = 0;
int height = src1.size().height;
int width = src1.size().width;
for (j = 0; j < height; j++)
{
for (i = 0; i < width; i++)
{
int watch1, watch2, watch3;
watch1 =src1.at<cv::Vec3b>(height - 1 - j, i)[0];
watch2 =src1.at<cv::Vec3b>(height - 1 - j, i)[1];
watch3 =src1.at<cv::Vec3b>(height - 1 - j, i)[2];
RGBQUAD c;
c.rgbBlue = watch1;
c.rgbGreen = watch2;
c.rgbRed = watch3;
dst.SetPixelColor(i, j, c);
}
}
以上代码段的重点在于双层for循环处,将PNG图片的三个通道颜色均转化为标准颜色库中的对应颜色。
优点:压缩比例较高;引入第三方库,实现较为简单。
缺点:图像压缩后易失真,对于噪声大的图片影响较为严重。
方法四:访问像素点进行压缩
直接使用内存访问图像像素点进行压缩。
void colorReduce8(cv::Mat &image, int div = 32)
{
int nl = image.rows;
int nc = image.cols;
//判断是否是连续图像,即是否有像素填充
if (image.isContinuous())
{
nc = nc*nl;
nl = 1;
}
int n =static_cast<int>(log(static_cast<double>(div)) / log(2.0));
uchar mask = 0xFF << n;
//遍历图像的每个像素
for (int j = 0; j<nl; ++j)
{
uchar *data =image.ptr<uchar>(j);
for (int i = 0; i<nc; ++i)
{
*data++ = *data &mask + div / 2;
*data++ = *data &mask + div / 2;
*data++ = *data &mask + div / 2;
}
}
}
以上代码段的重点在于双层for循环处,将PNG图片的颜色范围映射到一个更小的集合中,该方法压缩后的图片人为24位深度。
优点:位运算的计算速度快;压缩比例较高(与本身图片的质量有关)。
缺点:图像压缩后整体颜色偏暗。