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

目標

  • 加算、減算、ビット演算など、画像に対するいくつかの算術演算を学ぶ。
  • これらの関数を学ぶ: cv.add(), cv.addWeighted() など。

画像の加算

OpenCVの関数 cv.add() を使うか、単に numpy 演算 res = img1 + img2 によって2つの画像を加算できる。両方の画像は同じビット深度・型でなければならず、または2番目の画像は単なるスカラー値でもよい。

覚え書き
OpenCVの加算とNumpyの加算には違いがある。OpenCVの加算は飽和演算であるのに対し、Numpyの加算は剰余演算である。

例として、以下のサンプルを考える:

>>> x = np.uint8([250])
>>> y = np.uint8([10])
>>> print( cv.add(x,y) ) # 250+10 = 260 => 255
[[255]]
>>> print( x+y ) # 250+10 = 260 % 256 = 4
[4]
void add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1)
Calculates the per-element sum of two arrays or an array and a scalar.

これは2つの画像を加算するとより顕著になる。より良い結果が得られるため、OpenCVの関数を使うとよい。

画像のブレンディング

これも画像の加算であるが、ブレンディングや透明感を出すために画像に異なる重みを与える。画像は以下の式に従って加算される:

\[g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x)\]

\(\alpha\) を \(0 \rightarrow 1\) と変化させることで、ある画像から別の画像への滑らかなトランジションを実現できる。

ここでは2枚の画像をブレンドして合成する。1枚目の画像には重み0.7を、2枚目の画像には重み0.3を与える。cv.addWeighted() は画像に対して次の式を適用する。

\[dst = \alpha \cdot img1 + \beta \cdot img2 + \gamma\]

ここでは \(\gamma\) を0としている。

img1 = cv.imread('ml.png')
img2 = cv.imread('opencv-logo.png')
assert img1 is not None, "file could not be read, check with os.path.exists()"
assert img2 is not None, "file could not be read, check with os.path.exists()"
dst = cv.addWeighted(img1,0.7,img2,0.3,0)
cv.imshow('dst',dst)
void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1)
Calculates the weighted sum of two arrays.
void imshow(const String &winname, InputArray mat)
Displays an image in the specified window.
int waitKey(int delay=0)
Waits for a pressed key.
void destroyAllWindows()
Destroys all of the HighGUI windows.
Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
Loads an image from a file.

結果を以下に示す。

image

ビット演算

これにはビット単位のAND・OR・NOT・XOR演算が含まれる。これらは画像の任意の部分を抽出する際(後の章で見るように)や、矩形でないROIを定義して扱う際などに非常に有用である。以下では画像の特定領域を変更する例を見ていく。

ある画像の上にOpenCVのロゴを載せたいとする。2枚の画像を単純に加算すると色が変わってしまう。ブレンドすると透けた効果になる。しかしここでは不透明にしたい。もし矩形領域であれば、前章で行ったようにROIを使えばよい。だがOpenCVのロゴは矩形ではない。そこで以下に示すようにビット演算を使えば実現できる。

# Load two images
img1 = cv.imread('messi5.jpg')
img2 = cv.imread('opencv-logo-white.png')
assert img1 is not None, "file could not be read, check with os.path.exists()"
assert img2 is not None, "file could not be read, check with os.path.exists()"
# I want to put logo on top-left corner, So I create a ROI
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols]
# Now create a mask of logo and create its inverse mask also
img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY)
ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)
mask_inv = cv.bitwise_not(mask)
# Now black-out the area of logo in ROI
img1_bg = cv.bitwise_and(roi,roi,mask = mask_inv)
# Take only region of logo from logo image.
img2_fg = cv.bitwise_and(img2,img2,mask = mask)
# Put logo in ROI and modify the main image
dst = cv.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
cv.imshow('res',img1)
void bitwise_not(InputArray src, OutputArray dst, InputArray mask=noArray())
Inverts every bit of an array.
void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray())
computes bitwise conjunction of the two arrays (dst = src1 & src2) Calculates the per-element bit-wis...
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)
Converts an image from one color space to another.
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
Applies a fixed-level threshold to each array element.

結果を以下に示す。左の画像は作成したマスクを示す。右の画像は最終結果を示す。理解を深めるため、上記コード中の中間画像、特に img1_bg と img2_fg をすべて表示してみるとよい。

image

演習

  1. cv.addWeighted 関数を使い、フォルダ内の画像を画像間で滑らかにトランジションさせるスライドショーを作成せよ