Opencv关于imread和imwrite研习-Qt打开图像判断图像类型
今天要写一个判断是否为二值图,灰度图,彩色图的程序,本来逻辑没问题,但是Qt按钮始终在彩色图
于是单独读入图片,调试程序,发现,二值图和灰度图都是三通道,百思不得解,原来
我使用的opencv imread默认读取三通道彩色图
读图像的时候imread()函数的第二个参数使用的是默认值,那么这个时候都是以color形式读取的,所有就又变回3通道了;下面是第二个参数的介绍
flags – Flags specifying the color type of a loaded image:
– CV_LOAD_IMAGE_ANYDEPTH - If set, return 16-bit/32-bit image when the input hasthe corresponding depth, otherwise convert it to 8-bit.
– CV_LOAD_IMAGE_COLOR - If set, always convert image to the color one
– CV_LOAD_IMAGE_GRAYSCALE - If set, always convert image to the grayscale one
代码如下:
然后重新测试,发现依然总是选中那一个按钮,找错,发现,我的图像有问题,灰度图和二值图竟然是三通道,寻找问题,发现,我的图像为了测试方便,直接在opencv中变换后使用imwrite保存,但是imwrite保存会出现上述问题,寻找资料,发现
参考博客:
https://www.jianshu.com/p/fed6a8a99625
比如我有如下的一个233M的图片
经过下面的程序读进内存,再次保存后,图片容量就急剧变小了!
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat img = imread("src1.jpg");
imwrite("test.jpg", img);
return 0;
}
保存后的图片,只剩下126M了!怎么回事!我什么都没做啊,图片大小怎么就大大缩水了呢?
通过翻阅一些资料才知道,原来是图片格式惹得祸。其实有些图片格式是自带压缩的,比如jpg格式,而bmp格式的图片是不带任何压缩,这就是每种图片的特点,如果对这些知识点不清楚的话,很容易踩坑!平时我们操作的图像大小大多数都以KB为单位,所以经过一番“隐形压缩”后我们很难发现图片大小变小了,但是,当我们操作大图的时候,这种压缩效果一下子就看出来了。
那么如果我们在使用imwrite保存图片时想提高保存图片的质量,该如何操作?
要改变保存的图片的质量,关键在于imwrite函数的第三个参数。
先看imwrite的声明
CV_EXPORTS_W bool imwrite( const String& filename, InputArray img, const std::vector<int>& params = std::vector<int>());
第三个参数说明:const std::vector
•对于JPEG格式的图片,这个参数表示从0-100的图片质量(CV_IMWRITE_JPEG_QUALITY),默认值是95.
•对于PNG格式的图片,这个参数表示压缩级别(CV_IMWRITE_PNG_COMPRESSION)从0-9.较高的值意味着更小的尺寸和更长的压缩时间而默认值是3.
•对于PPM,PGM或PBM格式的图片,这个参数表示一个二进制格式标志(CV_IMWRITE_PXM_BINARY),取值为0或1,而默认值为1.
调整jpg图像格式的保存质量
opencv的imwrite默认存储的jpg图片质量为95,如果想进一步提高保存图片的质量,可以这么写
代码如下
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat img = imread("src1.jpg");
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY); //选择jpeg
compression_params.push_back(100); //在这个填入你要的图片质量
imwrite("test2.jpg", img, compression_params);
return 0;
}
可以看出,经过参数调整后,jpg格式保存的图片的大小有了很大的提升。
但是无论如何,以jpg格式保存图片还是不能百分百保存原图像的!
但是即使我们把图片质量写成100,图片质量跟原图还是右一定压缩的,比如原图233M,读入再保存为jpg格式容量就变为229M。
那当我们不断读入图片,又不断存储图片为jpg格式,图片的质量就会不断降低!
所以有以下总结:
第一,opencv的存储图片函数imwrite是可以通过第三个函数参数来调整保存图片的压缩比的,比如保存图片为jpg格式,我们如果我们写成
第二,jpg格式的图片读进内存,如果再保存为jpg格式后,容量会被压缩的,这是jpg格式的特性,怎么调整压缩比都避免不了失真(损失图片质量)。
此时,二值图的保存和灰度图的保存就没问题了
这里我选择的是jepg即jpg,如果你要选择其他格式保存,记得更改格式
enum
{
CV_IMWRITE_JPEG_QUALITY =1,
CV_IMWRITE_JPEG_PROGRESSIVE =2,
CV_IMWRITE_JPEG_OPTIMIZE =3,
CV_IMWRITE_JPEG_RST_INTERVAL =4,
CV_IMWRITE_JPEG_LUMA_QUALITY =5,
CV_IMWRITE_JPEG_CHROMA_QUALITY =6,
CV_IMWRITE_PNG_COMPRESSION =16,
CV_IMWRITE_PNG_STRATEGY =17,
CV_IMWRITE_PNG_BILEVEL =18,
CV_IMWRITE_PNG_STRATEGY_DEFAULT =0,
CV_IMWRITE_PNG_STRATEGY_FILTERED =1,
CV_IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY =2,
CV_IMWRITE_PNG_STRATEGY_RLE =3,
CV_IMWRITE_PNG_STRATEGY_FIXED =4,
CV_IMWRITE_PXM_BINARY =32,
CV_IMWRITE_WEBP_QUALITY =64,
CV_IMWRITE_PAM_TUPLETYPE = 128,
CV_IMWRITE_PAM_FORMAT_NULL = 0,
CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE = 1,
CV_IMWRITE_PAM_FORMAT_GRAYSCALE = 2,
CV_IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA = 3,
CV_IMWRITE_PAM_FORMAT_RGB = 4,
CV_IMWRITE_PAM_FORMAT_RGB_ALPHA = 5,
};
还有一点错误,打开二值图的时候,会跳到灰度图,我的判断是只有
255和0,但是我用的是大津法求阈值,好像不是只有255和0,偶尔还有1,254,之类的,查看了下阈值函数
/** Threshold types */
enum
{
CV_THRESH_BINARY =0, /**< value = value > threshold ? max_value : 0 */
CV_THRESH_BINARY_INV =1, /**< value = value > threshold ? 0 : max_value */
CV_THRESH_TRUNC =2, /**< value = value > threshold ? threshold : value */
CV_THRESH_TOZERO =3, /**< value = value > threshold ? value : 0 */
CV_THRESH_TOZERO_INV =4, /**< value = value > threshold ? 0 : value */
CV_THRESH_MASK =7,
CV_THRESH_OTSU =8, /**< use Otsu algorithm to choose the optimal threshold value;
combine the flag with one of the above CV_THRESH_* values */
CV_THRESH_TRIANGLE =16 /**< use Triangle algorithm to choose the optimal threshold value;
combine the flag with one of the above CV_THRESH_* values, but not
with CV_THRESH_OTSU */
};
如果使用了大津法之类的,需要其他方法判断,但是使用别的方法,需要自己判断阈值
纠结
最后我向现实屈服,先草率解决问题,有时间看源代码,看看为啥会有1和254等接近最大值最小值的数
最后附上,判断彩色图二值图灰度图的程序
if (text.channels() == 3){
int a = 3;
}
else if (text.channels() == 1)
{
int rowNumber = text.rows; //获取图像矩阵行数
int colNumber = text.cols; //三通道图像每行元素个数为列数x通道数
int pixelCount = 0;
for (int i = 0; i < rowNumber; i++)
{
uchar* pixelPtr = text.ptr<uchar>(i); //获取矩阵每行首地址指针
for (int j = 0; j < colNumber; j++)
{
if (pixelPtr[j] != 0 && pixelPtr[j] != 255)
{
pixelCount++;
}
}
}
if (pixelCount == 0) //二值图
{
int c = 3;
}
else{
int b = 3; //灰度图
}
}
}