OpenCV 4.13.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 4.13.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
画像に対する基本操作

目標

次のことを学ぶ:

  • ピクセル値へのアクセスと変更
  • 画像のプロパティへのアクセス
  • 関心領域 (ROI) の設定
  • 画像の分割と統合

本節のほぼすべての操作は、主にOpenCVよりもNumpyに関連している。OpenCVでより最適化されたコードを書くには、Numpyの十分な知識が必要である。

(ほとんどが1行程度のコードなので、例はPythonのターミナルで示す)

ピクセル値へのアクセスと変更

まずカラー画像を読み込む:

>>> import numpy as np
>>> import cv2 as cv
>>> img = cv.imread('messi5.jpg')
>>> assert img is not None, "file could not be read, check with os.path.exists()"
Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
Loads an image from a file.

ピクセル値には、その行と列の座標を使ってアクセスできる。BGR画像の場合は、青・緑・赤の値の配列が返される。グレースケール画像の場合は、対応する輝度だけが返される。

>>> px = img[100,100]
>>> print( px )
[157 166 200]
# accessing only blue pixel
>>> blue = img[100,100,0]
>>> print( blue )
157

ピクセル値も同じ方法で変更できる。

>>> img[100,100] = [255,255,255]
>>> print( img[100,100] )
[255 255 255]

警告

Numpyは高速な配列計算のために最適化されたライブラリである。したがって、各ピクセル値に単純にアクセスして変更するのは非常に遅く、推奨されない。

画像プロパティへのアクセス

画像プロパティには、行数、列数、チャンネル数、画像データの型、ピクセル数などが含まれる。

画像の形状(shape)は img.shape でアクセスする。行数・列数・チャンネル数(画像がカラーの場合)のタプルを返す:

>>> print( img.shape )
(342, 548, 3)
覚え書き
画像がグレースケールの場合、返されるタプルには行数と列数だけが含まれる。そのため、読み込んだ画像がグレースケールかカラーかを確認するのに適した方法である。

ピクセルの総数は img.size でアクセスする:

>>> print( img.size )
562248

画像のデータ型は `img.dtype` で取得する:

>>> print( img.dtype )
uint8
覚え書き
OpenCV-Pythonコードのエラーの多くは無効なデータ型が原因であるため、img.dtype はデバッグ時に非常に重要である。

画像のROI

ときには、画像の特定の領域を扱う必要がある。画像中の目の検出では、まず画像全体に対して顔検出を行う。顔が得られたら、画像全体を探索する代わりに、顔の領域だけを選択してその内側で目を探索する。これは精度(目は常に顔の上にあるため :D )と性能(小さな領域内を探索するため)を向上させる。

ROIも同様にNumpyのインデックス指定で取得する。ここではボールを選択し、それを画像内の別の領域へコピーしている:

>>> ball = img[280:340, 330:390]
>>> img[273:333, 100:160] = ball

以下の結果を確認すること:

image

画像チャンネルの分割と統合

ときには、画像のB、G、Rチャンネルを個別に扱う必要がある。この場合、BGR画像をシングルチャンネルに分割する必要がある。別の場合には、これらの個々のチャンネルを結合してBGR画像を作成する必要があるかもしれない。これは次のように簡単に行える:

>>> b,g,r = cv.split(img)
>>> img = cv.merge((b,g,r))
void split(const Mat &src, Mat *mvbegin)
Divides a multi-channel array into several single-channel arrays.
void merge(const Mat *mv, size_t count, OutputArray dst)
Creates one multi-channel array out of several single-channel ones.

または

>>> b = img[:,:,0]

赤いピクセルをすべてゼロに設定したいとする。その場合、まずチャンネルを分割する必要はない。Numpyのインデックス指定のほうが高速である:

>>> img[:,:,2] = 0

警告

cv.split() は(処理時間の点で)コストの高い操作である。そのため、必要な場合にのみ使用すること。それ以外の場合はNumpyのインデックス指定を使うこと。

画像への境界の作成(パディング)

写真の額縁のように画像の周囲に境界を作成したい場合は、cv.copyMakeBorder() を使用できる。ただし、畳み込み演算やゼロパディングなどへの応用も多い。この関数は次の引数を取る:

  • src - 入力画像
  • top, bottom, left, right - 対応する方向のピクセル数で表した境界の幅
  • borderType - Flag defining what kind of border to be added. It can be following types:
    • cv.BORDER_CONSTANT - 一定の色の境界を追加する。値は次の引数として与える。
    • cv.BORDER_REFLECT - 境界が境界要素の鏡像反射になる。次のような形: fedcba|abcdefgh|hgfedcb
    • cv.BORDER_REFLECT_101 または cv.BORDER_DEFAULT - 上記と同じだが、わずかに変化する。次のような形: gfedcb|abcdefgh|gfedcba
    • cv.BORDER_REPLICATE - 最後の要素が全体に複製される。次のような形: aaaaaa|abcdefgh|hhhhhhh
    • cv.BORDER_WRAP - 説明しにくいが、次のような形になる: cdefgh|abcdefgh|abcdefg
  • value - 境界の種類が cv.BORDER_CONSTANT の場合の境界の色

理解を深めるために、これらすべての境界の種類を示すサンプルコードを以下に示す:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = cv.imread('opencv-logo.png')
assert img1 is not None, "file could not be read, check with os.path.exists()"
replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
void copyMakeBorder(InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar &value=Scalar())
Forms a border around an image.

以下の結果を確認すること。(画像はmatplotlibで表示している。そのため赤と青のチャンネルが入れ替わる):

image