OpenCV中圖像顯示你不知道的編程技巧

  • 2019 年 10 月 6 日
  • 筆記

寫代碼我們是認真的! 閱讀本文大概需要 4min

OpenCV 中最常用的一個API函數 imshow 各種編程與應用技巧,是否有你以前一直想的,但是從來沒有成功過的操作!

最簡單的顯示方式

01

很多人學習OpenCV,學會前面兩個函數就是

Imread – 讀圖像  Imshow – 顯示圖像

代碼看起來是這樣

Mat src = imread("D:/images/test.png");  imshow("input", src);

覺得好簡單,真的好簡單,但是他們遇到大圖的時候,就會發現OpenCV無法完整顯示!想把多張圖像,顯示在一個窗口裏面,無法做到!顯示浮點數圖像全白!這些問題其實是你不了解如何正確使用imshow導致,下面就分享一下本人的做法,也許你會有更好的,歡迎留言拍磚!

浮點數圖像顯示的正確姿勢

02

上面的圖像,左側是輸入圖像,中間與右側都是浮點數圖像的顯示結果。中間圖像對應的代碼如下:

Mat m1;  src.convertTo(m1, CV_32F);  imshow("m1", m1);

顯示的結果是全白色,沒有任何可見的信息,難道是程序錯拉,程序沒有錯誤,Mat類型轉換從讀入圖像的CV_8UC3轉為CV_32FC3也沒有錯誤。修改一下代碼

Mat m2;  src.convertTo(m2, CV_32F, 0.00392);  imshow("m2", m2);

只是在類型轉換的時候多加了一個參數,這個參數是什麼 1/255 = 0.00392

意思是把像素值從0~255 轉換為0~1之間的浮點數,然後再顯示,顯示結果對應上圖最右側。

解釋:原來imshow顯示浮點數的時候,只支持0~1之間的浮點數顯示,超過1就認為是白色,所以在沒有對值域做rescale的時候,中間的浮點數Mat顯示只能是白色。

如何在一個Mat對象中顯示多張圖

03

這個是很多人問我過的問題,其實很簡單,創建一個空白的Mat,把兩張圖的內容放進去,然後顯示新創建的Mat對象就可以把兩張圖顯示在一個窗口裏面。先看效果

代碼實現如下:

Mat src1 = imread("D:/images/lena.png");  Mat src2 = imread("D:/images/t3.jpg");  imshow("src1", src1);  imshow("src2", src2);    // 構建新圖像的大小  int width = src1.cols + src2.cols;  int height = max(src1.rows, src2.rows);  Mat two = Mat::zeros(Size(width, height), src1.type());  // 構建ROI  Rect r1(0, 0, src1.cols, src1.rows);  Rect r2(0, 0, src2.cols, src2.rows);  r2.x = src1.cols;  // 內容copy  src1.copyTo(two(r1));  src2.copyTo(two(r2));    imshow("two images demo", two);  waitKey(0);

上述代碼,基本上已經很通用,直接讀入任意兩張圖像都可以,唯一需要注意的是合併之後圖像太大無法顯示怎麼辦,沒關係,我們這就來搞定這個問題。

圖像太大,無法完整顯示怎麼辦

04

這個問題,其實不能怪imshow,主要原因出在opencv的默認窗口創建上面,在OpenCV中你可以直接調用imshow函數去顯示圖像,默認會創建一個同名的窗口,這個窗口的默認打開模式是WINDOW_AUTOSIZE, 這種情況下你是無法調整窗口大小的,很多人其實是掉到這個坑裏面去的,解決辦法就是代碼顯式創建一個可以調整大小的窗口,一行代碼搞定:

namedWindow("input", WINDOW_FREERATIO)

然後調用

imshow("input", yourMat)

顯示時候,注意保持窗口名稱一致即可,再大的圖像顯示都沒有問題,前提是內存真的夠大!

千萬不要嘗試的Mat類型圖像顯示

Imshow其實只支持 CV_8U與CV_32F 類型的數據顯示,其它Mat類型數據最好先轉換為這兩種類型之一再顯示,不然你可能會得到各種錯誤,各種掉坑。建議不要嘗試跟API對着干,倒霉的只會是你自己。

收藏此帖,從此圖像顯示不會再有問題