ROI相關簡介
ROI是什么
ROI是region of interest首字母的簡寫宴凉,翻譯為感性趣的區(qū)域。其實在寫本篇之前應該寫一篇關于圖片是什么的學習筆記恬口,但又感覺里面沒多少東西還不能承載一篇學習筆記校读,所以這里只簡單提一下。
圖片是什么
其實大家也應該能猜到圖片就是一個二維數(shù)組祖能,只不過這個二維數(shù)組有點特殊歉秫,它有頭信息,在頭信息里會有描述這個二維數(shù)組的大小养铸、圖片類型和數(shù)組元素的數(shù)據(jù)類型等雁芙。下面是一張從官方教程里獲取的一張輔助理解的圖片轧膘。
上面的圖片只是一張灰色的圖片而我們經(jīng)常用的圖片彩色的圖片,在灰圖片中一個像素我們用一個值就可以表示了却特,但在彩色的圖片中一個像素要用3個值或4個值(有的圖片有alpha通道)來表示扶供。下面就是一個由三個值表示一個像素的輔助理解圖筛圆。
這張圖片是從官網(wǎng)獲取的裂明。是不是覺得顏色的排序有點不對呀,我們想的應該是紅在前才對太援,其實在OpenCV中很多圖片都是BGR格式的和我們常見的到RGB格式的存儲方式是相反的闽晦。具體為什么要用BGR格式還不清楚如有大神知道還請科普。其他圖片的格式有很多種如,HVS提岔、CyCbCr仙蛉、HSI等格式,后續(xù)可能會專門寫一篇關于圖片格式的學習筆記碱蒙,這里先對圖片格式的介紹寫這么多荠瘪。
為什么要設置ROI
上面我已經(jīng)介紹過圖片是一個二維數(shù)組,而我們有時處理圖片的時候只對其中的一部分圖片的區(qū)域進行處理赛惩,例如我們想在圖片某個區(qū)域打馬賽克哀墓,為了性能考慮我們可以只讓程序?qū)@一部分信息進行處理而將其他部分忽略,這時我們就要設置圖片感性趣的區(qū)域喷兼。設置完感性趣的區(qū)域后其實是指針指到了ROI區(qū)域的左上角篮绰,好像我們截取了一張小圖片一樣,我們只對這張小圖片進行處理就可以了季惯,因其ROI指向的還是原圖只在告訴它圖片的起始位置和大小變了吠各,所以在對ROI區(qū)操作會影響原圖。
設置ROI
在OpenCV中有C和C++的代碼勉抓,最早OpenCV是用C寫的贾漏,在開發(fā)中C的代碼寫起來不太方便在版本進入2.0之后后續(xù)加入的代碼改用C++,所以設置ROI的方法有兩種即C和C++的藕筋,C的已不常用不過這里還會列出已方便了解纵散。
C++
- (void)setImageROI:(cv::Mat)image{
// 設置ROI
// 方法一
cv::Mat roiImage = image(cv::Rect(100, 100, 200, 100));
// 方法二,第一個range表示起始行和終止行念逞,第二個range是起始列和終止列
//cv::Mat roiImage = testImage(cv::Range(100, 100 + 100), cv::Range(100, 200 + 100));
// 畫一個矩形
cv::rectangle(roiImage, cv::Rect(0, 0, 200, 100), cv::Scalar(255, 0, 0), 10);
}
設置ROI其實就是在原來圖片上指定一個區(qū)域困食,而這個區(qū)域只是新創(chuàng)建了一個圖片文件的頭信息而已并沒有產(chǎn)生新的圖片,文件頭里的圖片區(qū)域的起始位置指向了ROI區(qū)域的左上角位置翎承,所以在ROI上做的任何操作都會影響原圖片硕盹。
C
- (void)setImageROI:(IplImage *)image{
// 記錄圖片的大小和區(qū)域
CvRect currentRect = cvGetImageROI(image);
// 設置ROI區(qū)域
cvSetImageROI(image, cvRect(100, 100, 200, 100));
// 畫一個矩形
cvRectangleR(image, cvRect(0, 0, 200, 100), CvScalar(255, 0, 0), 10);
// 還原ROI區(qū)域
cvSetImageROI(image, currentRect);
// 上面的還原ROI區(qū)域要一個臨時變量,也可通過下面的方法叨咖,還原ROI區(qū)域而不用創(chuàng)建臨時變量
//cvResetImageROI(image);
}
對于C的代碼沒有生成一個文件頭信息而是修改原來的文件頭信息瘩例,所以要把文件頭信息改回去“〗海現(xiàn)在是不是覺得C++比C簡單多了。
代碼實戰(zhàn)
一垛贤、設置ROI并畫矩形
以下代碼是核心代碼焰坪,其他簡單的顯示代碼將不再列出。首先請導入以下頭文件聘惦。
#import <opencv2/opencv.hpp>
#import <opencv2/imgproc/types_c.h>
#import <opencv2/imgcodecs/ios.h>
然后下面是具體的ROI代碼都有注釋某饰,原理上面已說明。
- (UIImage *)getOpenCVImage{
// 獲取測試用的圖片路徑
NSString * path = [[NSBundle mainBundle] pathForResource:@"test" ofType:nil];
// 讀取圖片
cv::Mat testImage = cv::imread([path cStringUsingEncoding:NSUTF8StringEncoding]);
// 設置ROI
cv::Mat roiImage = testImage(cv::Rect(100, 100, 100, 100));
// 在ROI區(qū)域做操作善绎,畫一個矩形
cv::rectangle(roiImage, cv::Rect(5, 5, 50, 50), cv::Scalar(255, 255, 255), 10);
// 將圖片的格式從BGR轉換成RGB黔漂,如果不轉會造成顯示的圖片顏色出錯
cv::cvtColor(testImage, testImage, cv::COLOR_BGR2RGB);
// 返回UIImage類型的圖片
return MatToUIImage(testImage);
}
運行結果如下第一張是原圖,第二張是處理后的圖片:
可以看到我們在ROI的(0,0)位置開始畫矩形禀酱,但在大圖中實際效果卻不在左上角炬守,這就是設置ROI的效果。
超出ROI的效果
我們將上面代碼改成正以下代碼剂跟,讓畫矩形區(qū)域的高度大于ROI的高度减途。
// 放大矩形的高度,讓其超出ROI的區(qū)域
cv::rectangle(roiImage, cv::Rect(0, 0, 200, 150), cv::Scalar(255, 0, 0), 10);
可以看出曹洽,超出ROI的操作是被丟棄的鳍置。
二、設置ROI實現(xiàn)圖片移位
上面說過設置ROI后我們就可以只對該區(qū)域進行操作衣洁。我們練習一下將一ROI區(qū)域的數(shù)據(jù)放到另一個ROI區(qū)域墓捻。
- (UIImage *)getOpenCVImage{
// 獲取測試用的圖片路徑
NSString * path = [[NSBundle mainBundle] pathForResource:@"test" ofType:nil];
// 讀取圖片
cv::Mat testImage = cv::imread([path cStringUsingEncoding:NSUTF8StringEncoding]);
// 設置ROI區(qū)域A
cv::Mat roiImageA = testImage(cv::Rect(100, 100, 200, 100));
// 設置ROI區(qū)域B
cv::Mat roiImageB = testImage(cv::Rect(300, 30, 200, 100));
// 將roiImageB數(shù)據(jù)放到roiImageA的區(qū)域以實現(xiàn)圖片區(qū)域移動效果
roiImageB.copyTo(roiImageA);
// 將圖片的格式從BGR轉換成RGB,如果不轉會造成顯示的圖片顏色出錯
cv::cvtColor(testImage, testImage, cv::COLOR_BGR2RGB);
// 將圖片轉成UIImage并返回
return MatToUIImage(testImage);
}
代碼運行后結果: