? ??在圖像處理領域,ROI(Region of Interest)區域感興趣操作是非常基礎而重要的一環。無論是進行目標檢測、圖像分割,還是簡單的圖像處理,都離不開對圖像某一區域的選取與處理。本文將結合 OpenCV 的 C++ 接口,詳細介紹如何實現圖像的裁剪與 ROI 操作。
? ? ROI(Region of Interest)表示“感興趣區域”,是圖像中你想要單獨處理的一部分。例如,一張 1920×1080 的圖像中,我們只想處理中間 300×300 的區域,這個區域就稱為 ROI。在 OpenCV 中,ROI 通常通過設置圖像的矩形區域來實現。
?
設置 ROI 區域并裁剪圖像
// 定義一個矩形區域 ROI,位置(100, 100),大小(200×150)
cv::Rect roi(100, 100, 200, 150);// 使用 ROI 對圖像進行裁剪
cv::Mat cropped = img(roi);cv::imshow("裁剪后的圖像", cropped);
? ? 以上代碼實現了從大圖像(img)中提取一個局部區域(ROI)圖像cropped。
cv::Rect(x, y, width, height)
表示從(x, y)
點開始,寬為 width,高為 height。img(roi)
返回的是對原始圖像的一塊“視圖”,不復制數據,我們稱作為淺拷貝。
ROI 的復制與修改
因為 ROI 是視圖,所以對其修改會影響原圖。如果你不想修改原圖,應當使用 .clone()
方法。
// clone 后成為一塊新內存區域
cv::Mat roi_copy = cropped.clone();// 在 ROI 上畫一個綠色矩形
cv::rectangle(cropped, cv::Point(0, 0), cv::Point(199, 149), cv::Scalar(0, 255, 0), 2);cv::imshow("在 ROI 上畫矩形(影響原圖)", img);
cv::imshow("ROI 拷貝(不受影響)", roi_copy);
以上代碼中,clone函數返回新的內存數據區域,因此稱作深拷貝。我們在cropped上繪制一個矩形區域,由于cropped是img的淺拷貝,img數據上同樣也會繪制一個矩形。
?
用 ROI 做遮罩處理
// 創建一個遮罩
cv::Mat mask = cv::Mat::zeros(img.size(), CV_8UC1);
mask(roi).setTo(255); // 設置 ROI 區域為白色// 提取 ROI 區域內容
cv::Mat result;
img.copyTo(result, mask); // 使用遮罩復制內容cv::imshow("遮罩提取 ROI", result);
以上代碼生成了一個mask遮罩,對于mask矩陣中的非零區域被視作有效區域,因此函數copyTo僅拷貝mask中非零區域所對應的img像素。
?
在 ROI 上應用圖像處理(如模糊)
cv::Mat blurred;
cv::GaussianBlur(img(roi), blurred, cv::Size(15, 15), 0);// 將模糊圖像復制回原圖對應 ROI
blurred.copyTo(img(roi));cv::imshow("對 ROI 模糊處理后的圖像", img);
在OpenCV中,很多函數可以傳入一個ROI區域。因此我們在對圖像局部區域進行操作時,可以不需要重新生成新的局部圖像即可完成。但是注意一些特殊的函數可能不支持ROI區域操作,如cv::Mat::reshape(),cv::medianBlur()等。
?
完整代碼
int main() {cv::Mat img = cv::imread("lena.png");if (img.empty()) {std::cerr << "無法讀取圖像!" << std::endl;return -1;}// 定義 ROI 區域,這是一個200*150的區域,左上角坐標為(100,100)// cropped定義了一個 ROI 矩陣,但和img使用相同的數據區域cv::Rect roi(100, 100, 200, 150);cv::Mat cropped = img(roi);cv::imwrite("1_cropped.png", cropped);// 在 ROI 上畫框cv::rectangle(cropped, cv::Point(0, 0), cv::Point(199, 149), cv::Scalar(0, 255, 0), 2);cv::imwrite("2_rect.png", cropped);// ROI 的拷貝// 使用cv::Mat::clone函數進行深拷貝,roi_copy有單獨的數據內存cv::Mat roi_copy = cropped.clone();cv::imwrite("3_roi_copy.png", roi_copy);// 遮罩提取// 生成一個mask遮罩,在roi區域內為255,其他區域為0cv::Mat mask = cv::Mat::zeros(img.size(), CV_8UC1);mask(roi).setTo(255);cv::imwrite("4_mask.png", mask);// 使用mask遮罩拷貝數據,此時僅將img圖像中mask遮罩對應的數據拷貝到result中// 注意:copyTo也是深拷貝,并且該函數支持mask操作cv::Mat result;img.copyTo(result, mask);cv::imwrite("5_result.png", result);// 僅對 ROI 模糊處理// OpenCV中大多數函數支持基于ROI的操作,但有部分函數確不支持(需要特別留意)cv::Mat blurred;cv::blur(img(roi), blurred, cv::Size(15, 15));cv::imwrite("6_blurred.png", blurred);// 將模糊后圖像拷貝到原圖指定 ROI 上,copyTo支持 ROI 輸入blurred.copyTo(img(roi));cv::imwrite("7_img.png", img);return 0;
}

對局部區域進行平滑操作
?