前のチュートリアル: 行列に対するマスク操作
次のチュートリアル: OpenCVで2つの画像を加算(ブレンディング)する
入出力
画像
ファイルから画像を読み込む:
C++
Java
Mat img = Imgcodecs.imread(filename);
Python
jpgファイルを読み込むと、デフォルトでは3チャンネル画像が生成される。グレースケール画像が必要な場合は次を使う:
C++
Mat img =
imread(filename, IMREAD_GRAYSCALE);
Java
Mat img = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
Python
img =
cv.imread(filename, cv.IMREAD_GRAYSCALE)
- 覚え書き
- ファイルの形式はその内容(先頭の数バイト)によって決定される。画像をファイルに保存するには:
C++
Java
Imgcodecs.imwrite(filename, img);
Python
- 覚え書き
- ファイルの形式はその拡張子によって決定される。
- ファイルではなくメモリから/メモリへ画像を読み書きするには、cv::imdecode と cv::imencode を使う。
画像を用いた基本的な操作
ピクセル輝度値へのアクセス
ピクセル強度値を取得するには、画像の型とチャンネル数を知っておく必要がある。以下はシングルチャンネルのグレースケール画像(型8UC1)とピクセル座標x、yに対する例である:
C++
Java
byte[] imgData = new byte[(int) (img.total() * img.channels())];
img.get(0, 0, imgData);
byte intensity = imgData[y * img.cols() + x];
Python
C++版のみ: intensity.val[0] は0から255の値を保持する。xとyの順序に注意すること。OpenCVでは画像は行列と同じ構造で表現されるため、どちらの場合も同じ規約を用いる。すなわち、0始まりの行インデックス(またはy座標)が先で、0始まりの列インデックス(またはx座標)が後に続く。あるいは、次の表記を使うこともできる(C++のみ):
次に、BGRの色順を持つ3チャンネル画像(imreadが返すデフォルトの形式)を考える:
C++コード
Python Python
_blue = img[y,x,0]
_green = img[y,x,1]
_red = img[y,x,2]
浮動小数点画像に対しても同じ方法が使える(例えば3チャンネル画像にSobelを適用するとそのような画像が得られる)(C++のみ):
float blue = intensity.
val[0];
float green = intensity.
val[1];
float red = intensity.
val[2];
同じ方法でピクセル強度を変更することもできる:
C++
img.at<
uchar>(y, x) = 128;
Java
byte[] imgData = new byte[(int) (img.total() * img.channels())];
imgData[y * img.cols() + x] = (byte) 128;
img.put(0, 0, imgData);
Python
OpenCVには、特にcalib3dモジュールに、cv::projectPoints のように、Mat形式の2Dまたは3D点の配列を受け取る関数がある。行列はちょうど1列を含む必要があり、各行が1つの点に対応し、行列の型はそれぞれ32FC2または32FC3でなければならない。このような行列は std::vector から容易に構築できる(C++のみ):
この行列内の点には、同じ方法 Mat::at でアクセスできる(C++のみ):
メモリ管理と参照カウント
Matは、行列/画像の特性(行数や列数、データ型など)とデータへのポインタを保持する構造体である。したがって、同じデータに対応するMatのインスタンスを複数持つことを妨げるものは何もない。Matは参照カウントを保持しており、特定のMatインスタンスが破棄される際にデータを解放すべきかどうかを示す。以下はデータをコピーせずに2つの行列を作成する例である(C++のみ):
std::vector<Point3f> points;
その結果、1列の32FC3行列ではなく3列の32FC1行列が得られる。pointsMat はpointsのデータを使用し、破棄されてもメモリを解放しない。ただしこの特定の例では、開発者は points の生存期間が pointsMat よりも長いことを保証しなければならない。データをコピーする必要がある場合は、例えば cv::Mat::copyTo や cv::Mat::clone を用いて行う:
C++
Java
Mat img = Imgcodecs.imread("image.jpg");
Mat img1 = img.clone();
Python
各関数には空の出力Matを渡すことができる。各実装は出力先の行列に対してMat::createを呼び出す。このメソッドは、行列が空であればデータを割り当てる。空でなく、正しいサイズと型を持っていれば、何もしない。ただし、サイズや型が入力引数と異なる場合は、データが解放され(失われ)、新しいデータが割り当てられる。例えば:
C++
Java
Mat img = Imgcodecs.imread("image.jpg");
Mat sobelx = new Mat();
Imgproc.Sobel(img, sobelx, CvType.CV_32F, 1, 0);
Python
_sobelx =
cv.Sobel(img, cv.CV_32F, 1, 0)
基本的な演算
行列には便利な演算子が多数定義されている。例えば、既存のグレースケール画像 img から黒画像を作る方法は次のとおりである
C++
Java
byte[] imgData = new byte[(int) (img.total() * img.channels())];
Arrays.fill(imgData, (byte) 0);
img.put(0, 0, imgData);
Python
関心領域(ROI)を選択する:
C++
Rect r(10, 10, 100, 100);
Java
Mat smallImg = img.submat(r);
Python
_smallImg = img[10:110,10:110]
カラーからグレースケールへの変換:
C++
Java
Mat img = Imgcodecs.imread("image.jpg");
Mat grey = new Mat();
Imgproc.cvtColor(img, grey, Imgproc.COLOR_BGR2GRAY);
Python
画像の型を8UC1から32FC1に変更する:
C++
Java
src.convertTo(dst, CvType.CV_32F);
Python
_dst = src.astype(np.float32)
画像の可視化
開発過程でアルゴリズムの中間結果を確認できることは非常に有用である。OpenCVは画像を可視化する便利な手段を提供する。8U画像は次のように表示できる:
C++
Java
Mat img = Imgcodecs.imread("image.jpg");
HighGui.namedWindow("image", HighGui.WINDOW_AUTOSIZE);
HighGui.imshow("image", img);
HighGui.waitKey();
Python
waitKey()の呼び出しは、「image」ウィンドウでのキー入力を待つメッセージパッシングサイクルを開始する。32F画像は8U型に変換する必要がある。例えば:
C++
double minVal, maxVal;
sobelx.
convertTo(draw,
CV_8U, 255.0/(maxVal - minVal), -minVal * 255.0/(maxVal - minVal));
Java
Mat img = Imgcodecs.imread("image.jpg");
Mat grey = new Mat();
Imgproc.cvtColor(img, grey, Imgproc.COLOR_BGR2GRAY);
Mat sobelx = new Mat();
Imgproc.Sobel(grey, sobelx, CvType.CV_32F, 1, 0);
MinMaxLocResult res = Core.minMaxLoc(sobelx);
Mat draw = new Mat();
double maxVal = res.maxVal, minVal = res.minVal;
sobelx.convertTo(draw, CvType.CV_8U, 255.0 / (maxVal - minVal), -minVal * 255.0 / (maxVal - minVal));
HighGui.namedWindow("image", HighGui.WINDOW_AUTOSIZE);
HighGui.imshow("image", draw);
HighGui.waitKey();
Python
sobelx =
cv.Sobel(grey, cv.CV_32F, 1, 0)
minVal = np.amin(sobelx)
maxVal = np.amax(sobelx)
draw =
cv.convertScaleAbs(sobelx, alpha=255.0/(maxVal - minVal), beta=-minVal * 255.0/(maxVal - minVal))
- 覚え書き
- ここで cv::namedWindow は不要である。なぜなら直後に cv::imshow が続くからである。とはいえ、ウィンドウのプロパティを変更したい場合や cv::createTrackbar を使う場合には利用できる