OpenCV ROI - eiichiromomma/CVMLAB GitHub Wiki

(OpenCV) ROI Region of Interest

Region Of Interest:着目領域(要するにウィンドウ)を使うと楽になる?

OpenCV Multi-viewも参照

ROI

ROIはある領域だけ処理を施したい場合に指定する。OpenCVでは矩形のみ指定可能。

大きい画像を幾つかの領域に分けて処理をしたい時に有用

C++でのROI

使い方

Matが標準になったのでcheatsheetより

Mat imageroi = image(Rect(10,20,100,100));

としてimageroiを弄るとimageへ変更が反映される。

処理後にIplImageのようなResetは不要。

注意点

MatにはROIの概念が無いので,Rectで絞った領域を新たなMatとして処理する。

Mat imageroi1 = image1(Rect(10,20,100,100));
Mat imageroi2 = image2(Rect(30,40,100,100));

のように2つのROIを設定し,ROIの内容をコピーしたい場合には

imageroi1.copyTo(imageroi2);

のようにROIとしたMat同士で処理する。

Python cv2でのROI

import cv2
import numpy as np
img = cv2.imread('lena.jpg',cv2.IMREAD_ANYCOLOR)
cv2.imshow('src',img)
# (10,50)-(20,80)の矩形をROIとする
imgROI1 = img[50:80, 10:20]
cv2.imshow('roi',imgROI1)
# ROIを0で塗り潰す
imgROI1[:,:,:] = 0
# 再表示するとROIの操作が反映されているのが分かる
cv2.imshow('src',img)

PythonでのROI (旧)

cv.GetSubRectを使う。感覚としてはC++に近い。

SetImageROIでの方法

IplImageはROIが指定でき、随時変更、リセットができる。

指定方法

cvSetImageROI(画像, 矩形情報);

画像imgに(10,10)を始点とした幅、高さが50pixelのROIを指定すると

cvSetImageROI(img, cvRect(10,10,50,50));

となる。

ちなみに

cvResetImageROI(img);

で解除。

注意点

  • ROIが有効なのはOpenCVのAPIのみ
    • 画像データのポインタを直接叩く場合は非適用
  • cvSub等の演算を行なう場合は演算の相手に同じ大きさの画像を使うか、同じ大きさのROIを指定しなければならない
  • 出力画像の大きさはROIではなく画像と同じにし、同じROIを指定する。
    • 要するに元画像にROIを指定してからcvCloneImageするのが楽

実験

画像を読んでR,G,B成分に分解し、RからGを引いた画像を表示する。但し、ROIを(10,10)-(61,61)に指定し、ポインタを直接叩いて(50,50)-(99,99)を黒く塗り潰す。

    #include <stdio.h>
    #include <cv.h>
    #include <highgui.h>
    int main(int argc, char *argv[])
    {
      IplImage* srcImg = 0; 
      IplImage* redchannelImg = 0;
      IplImage* greenchannelImg = 0;
      IplImage* bluechannelImg = 0;
      IplImage* outImg = 0;
      
      if(argc<2){
        printf("Usage: main <image-file-name>\n\7");
        exit(0);
    
      //画像読み込み
      srcImg=cvLoadImage(argv[1],1);
      if(!srcImg){
        printf("Could not load image file: %s\n",argv[1]);
        exit(0);
      }
      //チャネル画像作成
      redchannelImg = cvCreateImage(cvSize(srcImg->width,srcImg->height),IPL_DEPTH_8U,1);
      greenchannelImg = cvCreateImage(cvSize(srcImg->width,srcImg->height),IPL_DEPTH_8U,1);
      bluechannelImg = cvCreateImage(cvSize(srcImg->width,srcImg->height),IPL_DEPTH_8U,1);
    
      //各チャネルに分解
      cvCvtPixToPlane(srcImg,bluechannelImg,greenchannelImg,redchannelImg,0);
    
      // create a window
      cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE); 
      cvMoveWindow("mainWin", 100, 100);
      //ROI指定
      cvSetImageROI(redchannelImg,cvRect(10,10,50,50));
      cvSetImageROI(greenchannelImg,cvRect(10,10,50,50));
      //出力先指定 cvCloneImageでROIまるごとコピー
      outImg=cvCloneImage(redchannelImg);
      cvSub(redchannelImg,greenchannelImg,outImg,0);
      //APIを使わずにポインタから直接画像を弄ると…
      for (int y=50; y<100; y++)
        for (int x=50; x<100; x++)
          (outImg->imageData+outImg->widthStep*y)[x] = 0;
      //これをしないとROIのみ表示される
      cvResetImageROI(outImg);
      //画像の表示
      cvShowImage("mainWin", outImg );
    
      // wait for a key
      cvWaitKey(0);
    
      // release the image
      cvReleaseImage(&srcImg );
      cvReleaseImage(&redchannelImg);
      cvReleaseImage(&greenchannelImg);
      cvReleaseImage(&bluechannelImg);
    }

こんな感じの結果になる。

⚠️ **GitHub.com Fallback** ⚠️