1. 程式人生 > >Opencv關於imread和imwrite研習-Qt開啟影象判斷影象型別

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儲存會出現上述問題,尋找資料,發現

參考部落格:

比如我有如下的一個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; //灰度圖

		}

	}
}