C++ opencv Image visual enhancement - false color(圖像視覺效果增強-僞彩色)

今天,抽短暫時間實現了一個新的功能,那就是16位圖像的讀取以及僞彩色視覺效果增強。個人感覺各種語言還是C++好用,PY雖然很火,但是項目中執行效率是真的難受。

  • --->Today, a new feature has been briefly implemented, which is the ability to read 16-bit images and enhance false-color visuals.I personally feel that various languages are still good for C++,python is very popular, but the execution efficiency in the project is really uncomfortable.

如果你真的瞭解opencv等,你會發現,opencv默認讀取的是8位圖像數據,如果需要讀取16位深度的圖像,你需要進行相應的處理。你會奇怪位深度對於一個圖像有什麼用,位深度用於指定圖像中的每個像素可以使用的顏色信息數量。每個像素使用的信息位數越多,可用的顏色就越多,顏色表現就更逼真。例如,位深度爲 1 的圖像的像素有兩個可能的值:黑色和白色。位深度爲 8 的圖像有 28(即 256)個可能的值。位深度爲 8 的灰度模式圖像有 256 個可能的灰色值。RGB 圖像由三個顏色通道組成。8 位/像素的 RGB 圖像中的每個通道有 256 個可能的值,這意味着該圖像有 1600 萬個以上可能的顏色值。有時將帶有 8 位/通道 (bpc) 的 RGB 圖像稱作 24 位圖像(8 位 x 3 通道 = 24 位數據/像素)。除了 8 位/通道的圖像之外,Photoshop 還可以處理包含 16 位/通道或 32 位/通道的圖像。包含 32 位/通道的圖像也稱作高動態範圍 (HDR) 圖像。

  • --->If you really understand opencv and so on, you will find that opencv reads 8-bit image data by default, and if you need to read 16-bit depth image, you need to process accordingly.You wonder what bit depth is good for an image. Bit depth is used to specify the amount of color information that each pixel in the image can use.The more bits of information each pixel USES, the more colors are available and the more realistic the color presentation.For example, the pixels of an image with a bit depth of 1 have two possible values: black and white.An image with a bit depth of 8 has 28(256) possible values.A grayscale image with a bit depth of 8 has 256 possible gray values.The RGB image consists of three color channels.Each channel in an 8-bit/pixel RGB image has 256 possible values, which means that the image has more than 16 million possible color values.RGB images with 8 bit/channel (BPC) are sometimes referred to as 24 bit images (8 bit x 3 channel = 24 bit data/pixel).In addition to 8-bit/channel images, Photoshop can also process images containing 16-bit/channel or 32-bit/channel.Images containing 32 bits/channels are also known as high dynamic range (HDR) images.

灰度是描述灰度圖像內容的最直接的視覺特徵。它指黑白圖像中點的顏色深度,範圍一般從0到255,白色爲255,黑色爲0,故黑白圖像也稱灰度圖像。灰度圖像矩陣元素的取值通常爲[0,255],因此其數據類型一般爲8位無符號整數,這就是人們通常所說的256級灰度。將灰度圖像轉換爲彩色圖像,稱爲灰度圖像的僞彩色處理。僞彩色處理技術的實現方式有很多,如:灰度分割法、灰度級-彩色變換法、濾波法等等。以下采用的是灰度級-彩色變換法,這是將來自傳感器的灰度圖像送入三個不同特徵的R、G、B變換器,然後將三種變換器的不同輸出分別送到彩色顯示器進行顯示的技術。

  • ---->Grayscale is the most direct visual feature to describe the content of grayscale image.It refers to the color depth of the point in the black and white image, ranging from 0 to 255, white is 255, black is 0, so the black and white image is also called grayscale image.The value of the gray-scale image matrix element is usually [0,255], so its data type is generally an 8-bit unsigned integer, which is commonly referred to as the 256-level gray-scale.The transformation of grayscale image into color image is called pseudo-color processing of grayscale image.There are many ways to realize the pseudo-color processing technology, such as: gray segmentation method, gray grade-color transformation method, filtering method and so on.The following is the graygrade-color transformation method, which is used to feed the grayscale image from the sensor into the R, G, and B converters with three different features, and then send the different outputs of the three converters to the color display for display.

你能在圖像屬性查看位深--->

  • ---->You can see the bit depth in the image properties -->

 瞭解這些之後,你可以進行opencv加載16位圖像數據,其實,準確來說,不管以哪一種形式進行加載,對於人的視覺來說差距不是特別大,對於windows來說會進行優化,最後都轉換爲8位進行顯示,參考我的代碼,你能實現16位圖像的讀取。

  • ---->After understanding these, you can use opencv to load 16-bit image data, in fact, precisely, no matter in what kind of form to load, for human visual difference is not particularly big, for Windows will be optimized, finally converted to 8 bits for display, refer to my code, you can read the 16-bit image.
Mat img = imread("./1.tif", cv::IMREAD_LOAD_GDAL | cv::IMREAD_ANYDEPTH);
//-------------------------------------------------------------
cout << "源文件位深度:"<<img.depth() << endl;
//-------------------------------------------------------------
//-------------------------------------------------------------
Mat image(img.rows,img.cols,CV_16U);
for (int i = 0;i < image.rows;i++)
{
	for (int j = 0;j < image.cols;j++)
	{
		image.at<short>(i, j) = img.at<short>(i, j);
		//注意這裏.at<>尖括號裏的類型是16位圖對應的short類型不是8位圖對應的uchar類型
	}
}
//------------------------------------------------

這樣的話輸出的源文件的位深度就是16位,如果直接進行讀取,獲取到的就是8位深度。

  • ---->In this case, the bit depth of the output source file is 16 bit, and if it is read directly, it will get 8 bit.

接下來定義三個單通道RGB,定義爲16位深度。參考我下面的代碼:

  • ---->Then, i define three single-channel RGB, a 16-bit depth,channel.Refer to my code below:
//------------------------------------------------
Mat R(image.rows,image.cols,CV_16U);
Mat G(image.rows,image.cols,CV_16U);
Mat B(image.rows,image.cols,CV_16U);
R = image.clone();
G = image.clone();
B = image.clone();
cout << "R文件位深度:"<< R.depth() << endl;
cout << "G文件位深度:"<< G.depth() << endl;
cout << "B文件位深度:"<< B.depth() << endl;
//------------------------------------------------

那麼,如何將16位數據進行僞彩色的轉換呢,這是個問題,值得思考。 

映射關係如下,其中R(x,y)、G(x,y)、B(x,y)分別表示R、G、B通道的顏色值,f(x,y)表示特定點灰度圖像的灰度值,f是所選灰度圖像的灰度值。但是,你得明白,這裏的關係是8位圖對應的轉換。

  • ---->So, how to convert 16-bit data to pseudo-color is a problem worth thinking about.
  • The mapping relationship is as follows, where R(x,y), G(x,y) and B(x,y) represent the color values of channels R, G and B, respectively; f(x,y) represents the gray value of the grayscale image of a specific point; f is the gray value of the selected gray image.However, you have to understand that the relationship here is the transformation of 8 bitmaps.

 我進行了簡單的對應處理,這個很簡單的,就是一個線性對應而已,但是你必須得知道,這個是不好的,但是是可以這麼做的。

---->I did a simple correspondence, this is a very simple one, it's just a linear correspondence, but you have to know, this is bad, but you can do it this way.

int rows = image.rows;
int cols = image.cols;
for (int i = 0; i < rows; i++)
{
	for (int j = 0; j < cols; j++)
	{
		int current = image.at<short>(i, j);//uchar 8位
		if ( current  >= 0 && current <= 16448)
		{
			R.at<short>(i, j) = 0;
			G.at<short>(i, j) = 4 * current;
			B.at<short>(i, j) = 65535;
		}
		else if (16448 < current && current <= 32896)
		{
			R.at<short>(i, j) = 0;
			G.at<short>(i, j) = 65535;
			B.at<short>(i, j) = (-4)*(current-32896);
		}
		else if (32896 < current && current <= 49344)
		{
			R.at<short>(i, j) = 4 * (current - 32896);
			G.at<short>(i, j) = 65535;
			B.at<short>(i, j) = 0;
		}
		else
		{
			R.at<short>(i, j) = 65535;
			G.at<short>(i, j) = (-4)*(current - 65535);
			B.at<short>(i, j) = 0;
		}

	}
}

最後,就是三個通道的合併,使用函數merge()。

merge()函數:split()函數的逆向操作——將多個數組合併成一個多通道數組,將給定的這些孤立的單通道數組合併成一個多通道數組,從而創建一個由多個單通道陣列組成的多通道陣列。

原型:<1>C++: void merge(const Mat* mv, size_tcount, OutputArray dst);
          <2>C++: void merge(InputArrayofArrays mv,OutputArray dst);

 變量介紹如下:
        第一個參數:mv,填需要被合併的輸入矩陣 或 vector容器的陣列;
        第二個參數:count,當mv爲一空白C數組時,代表輸入矩陣的個數,顯然必須大於1;
        第三個參數:dst,即輸出矩陣,和mv[0]具有相同的尺寸和深度,並且通道的數量是矩陣陣列中通道的總數。

  • ---->Finally, it's a merge of three channels, using the function merge().

    Merge () function: the reverse of the split() function, which merges multiple arrays into a multichannel array, merges a given set of isolated single-channel arrays into a multichannel array to create a multichannel array consisting of multiple single-channel arrays.

    Prototype: <1>C++: void merge(const Mat* mv, size_tcount, OutputArray dst);
                     <2>C++: void merge(InputArrayofArrays mv,OutputArray dst);

Variables are introduced as follows:

(1)The first parameter: mv, filling the array of input matrix or vector containers that need to be merged;

        (2)The second parameter: count, when mv is a blank C array, represents the number of input matrix, which must be greater than 1 obviously;

       (3)The third parameter: DST, the output matrix, has the same size and depth as mv[0], and the number of channels is the total number of channels in the matrix array.

Mat imgArray[3];
imgArray[0] = R;
imgArray[1] = G;
imgArray[2] = B;
Mat newImg;
merge(imgArray, 3, newImg);
cout << "out文件位深度:"<< newImg.depth() << endl;
imwrite("./16_24output.tif",newImg);

結果:

  • ---->result:

 my main code:

//---------------------------------------------------------------------
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    /*
    例如:一幅畫的尺寸是1024*768,深度爲16,則它的數據量爲1.5M。
    計算如下:102476816bit=(102476816)/8字節=[(102476816)/8]/1024KB={[(102476816)/8]/1024}/1024MB。

    深度組合
    輸入深度(src.depth()) 輸出深度(ddepth)
    CV_8U -1 / CV_16S / CV_32F / CV_64F
    CV_16U / CV_16S -1 / CV_32F / CV_64F
    CV_32F -1 / CV_32F / CV_64F
    CV_64F -1 / CV_64F
    注意
    當ddepth = -1時,輸出圖像將具有與源相同的深度。
    */
    /*depth 圖像元素的位深度,可以是下面的其中之一:
                 位深度                                      取值範圍
    IPL_DEPTH_8U - 無符號8位整型                               0--255
    IPL_DEPTH_8S - 有符號8位整型                             -128--127
    IPL_DEPTH_16U - 無符號16位整型                             0--65535
    IPL_DEPTH_16S - 有符號16位整型                       -32768--32767
    IPL_DEPTH_32S - 有符號32位整型                              0--65535
    IPL_DEPTH_32F - 單精度浮點數                               0.0--1.0
    IPL_DEPTH_64F - 雙精度浮點數                                0.0--1.0
    */
    /*
    Mat_<uchar>對應的是CV_8U,Mat_<char>對應的是CV_8S,
    Mat_<int>對應的是CV_32S,Mat_<float>對應的是CV_32F,
    Mat_<double>對應的是CV_64F,對應的數據深度如下:
    • CV_8U - 8-bit unsigned integers ( 0..255 )
    • CV_8S - 8-bit signed integers ( -128..127 )
    • CV_16U - 16-bit unsigned integers ( 0..65535 )
    • CV_16S - 16-bit signed integers ( -32768..32767 )
    • CV_32S - 32-bit signed integers ( -2147483648..2147483647 )
    • CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )
    • CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )
    */
    /*
        #define CV_8U   0
        #define CV_8S   1
        #define CV_16U  2
        #define CV_16S  3
        #define CV_32S  4
        #define CV_32F  5
        #define CV_64F  6
        #define CV_USRTYPE1 7
    */
    /*
   merge()函數:split()函數的逆向操作——將多個數組合併成一個多通道數組,將給定的這些孤立的單通道數組合併成一個多通道數組,從而創建一個由多個單通道陣列組成的多通道陣列。
     原型:<1>C++: void merge(const Mat* mv, size_tcount, OutputArray dst);
          <2>C++: void merge(InputArrayofArrays mv,OutputArray dst);
    變量介紹如下:
        第一個參數:mv,填需要被合併的輸入矩陣 或 vector容器的陣列;
        第二個參數:count,當mv爲一空白C數組時,代表輸入矩陣的個數,顯然必須大於1;
        第三個參數:dst,即輸出矩陣,和mv[0]具有相同的尺寸和深度,並且通道的數量是矩陣陣列中通道的總數。
    */
    //===================================================================================================
    //===================================================================================================
    //_8bit_24bit();
    //===================================================================================================
    //===================================================================================================
    _16bit_48bit();
    return a.exec();
}

 ​​​I hope I can help you,If you have any questions, please  comment on this blog or send me a private message. I will reply in my free time.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章