【OpenCV-Python】resize(画像の拡大縮小)

OpenCVで画像のリサイズを行うには、resize関数を用います。

resize関数では、リサイズ後の画像の大きさ(幅と高さ)を指定する方法と、リサイズのスケールを指定する方法があります。

構文

resize( src, dsize[, dst[, fx[, fy[, interpolation]]]] ) -> dst
src リサイズを行う画像データを指定します。
dsize リサイズ後の画像サイズ(幅, 高さ)を指定します。
倍率(fx, fy)を指定するときは、Noneを指定します。
fx 横方向の倍率を指定します。
fy 縦方向の倍率を指定します。
interpolation 補間モードを以下の中から指定します。
cv2.INTER_NEAREST
cv2.INTER_LINEAR
cv2.INTER_CUBIC
cv2.INTER_AREA
cv2.INTER_LANCZOS4

 

出力サイズを指定してリサイズする方法

リサイズ後のサイズを(幅, 高さ)を指定してリサイズを行います。

サンプルプログラム

import cv2

# 画像の読込
src = cv2.imread("image.bmp", cv2.IMREAD_UNCHANGED);

# 出力サイズ(幅、高さ)を指定してリサイズ
dst = cv2.resize(src, (400, 200))

# 画像の表示
cv2.imshow("Src Image", src)
cv2.imshow("Resize Image", dst)
cv2.waitKey()

実行結果

倍率を指定してリサイズする方法

倍率はfx, fyを指定するのですが、出力後のサイズ(dsize)は省略できないので、dsizeにNoneを指定します。

指定方法は

dst = cv2.resize(src, None, None, 0.8, 1.2)

や、変数名を指定して

dst = cv2.resize(src, None, fx = 0.8, fy = 1.2)

のようにします。

サンプルプログラム

import cv2

# 画像の読込
src = cv2.imread("image.bmp", cv2.IMREAD_UNCHANGED);

# スケール(横方向、縦方向)を指定してリサイズ
dst = cv2.resize(src, None, None, 0.8, 1.2)

# 画像の表示
cv2.imshow("Src Image", src)
cv2.imshow("Resize Image", dst)
cv2.waitKey()

実行結果

補間方法の指定

リサイズ時の補間方法については

cv2.INTER_NEAREST
cv2.INTER_LINEAR
cv2.INTER_CUBIC
cv2.INTER_AREA
cv2.INTER_LANCZOS4

の中から指定します。

指定方法は

dst = cv2.resize(src, None, None, 0.8, 1.2, cv2.INTER_NEAREST)

や、変数名を指定して

dst = cv2.resize(src, None, fx = 0.8, fy = 1.2, interpolation = cv2.INTER_NEAREST)

のようにします。

 

補間モードについてはこちら↓を参照ください。

【OpenCV-Python】アフィン変換(同次座標系を使用)

 

補間そのものについてはこちら↓を参照ください。

画素の補間(Nearest neighbor,Bilinear,Bicubic)の計算方法

 

参照ページ

https://docs.opencv.org/4.6.0/da/d54/group__imgproc__transform.html#ga47a974309e9102f5f08231edc7e7529d

【OpenCV-Python】JPEG画像の品質を指定して保存する

OpenCVで画像をファイルに保存するには imwrite 関数を用いますが、この関数でjpegファイルの品質を指定して保存することが可能です。

imwrite関数の書式は

imwrite(filename, img[, params]) ->retval
引数 説明
filename ファイル名
img 画像データ
params オプション設定(省略可)

 

となりますが、paramsの部分に jpegファイルの品質の値(0~100)を指定することが可能です。

品質を指定して保存するサンプルは以下の通りです。

import cv2

# 画像を開く
img = cv2.imread("Mandrill.bmp", cv2.IMREAD_UNCHANGED)

# JPEGで品質(75)を指定して画像を保存する
cv2.imwrite("Mandrill_q75.jpg", img, [cv2.IMWRITE_JPEG_QUALITY, 75])

品質の値による画像の違いは、Pillowのときの例を参照ください↓

【Python/Pillow(PIL)】JPEG画像の品質を指定して保存する

 

Pillowでは品質の初期値が75であったのに対して、OpenCVでは95になります。

OpenCVでは画像処理用として画像ファイルに保存されることが多いので、品質の値が大きめな初期値になっているのだと思いますが、品質95だと、jpeg画像特有のモスキートノイズのようなノイズは見た目上、ほぼ無いものの、輝度値レベルで見ると、1程度の計算誤差レベル?の誤差はあります。

画像処理用として画像ファイルに保存するには、基本的にはビットマップファイル(*.bmp)に保存することをおススメします。

参考ページ

https://docs.opencv.org/4.6.0/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce

https://docs.opencv.org/4.6.0/d8/d6a/group__imgcodecs__flags.html#ga292d81be8d76901bff7988d18d2b42ac

ハイパースペクトルカメラとは?その原理は?

ハイパースペクトルカメラとは?

ハイパースペクトルカメラとは、1回の撮影で多くの波長(例えば100波長分など)ごとの画像を撮影できるカメラとなります。

多くの波長の画像を取得できると何がいいか?というと、撮影する被写体によって、特定の波長で暗くみえたりするのですが、この特定波長というのが、材料や状態(水分を多く含むなど)によって異なるため、材料の分類やキズの検出が可能になります。

具体的には食品の中に含まれる異物の検出や、農作物の打痕、リサイクル材料の分類など、一般的なカメラで撮影した画像だけでは困難な検査も可能になります。

ただ、実際には複数の分類が必要でない場合には、検査したい被写体がどのような波長特性を持つのか?を解析的に撮影し、実際の検査では、特徴的な波長だけで撮影するようにバンドパスフィルタを使って、一般的なカメラで撮影する場合もあります。

 

ハイパースペクトルカメラで撮影した画像

下の写真は、ポリスチレン、ポリプロピレン、アクリル、生米、ナイロンを一般的なカラーカメラで撮影した画像になりますが、この画像を通常の画像処理で分類しようとすると、ほぼ白いか、透明なので、これを分類するのは、意外と難しかったりもします。

 

この被写体を実際にハイパースペクトルカメラで撮影し、各波長ごとの画像を並べた物が以下の動画になります。

ここでの注目ポイントとしては波長を大きくしていくと、特定の波長で暗くなり、さらに波長を大きくすると、元の明るさに戻ったりしています。

この特定の波長というのが、材質により異なっています。

上の動画で、各材料ごとの輝度変化を横軸に波長、縦軸に輝度値をプロットした物が以下のグラフになります。

このグラフを見ると、例えばポリスチレンの1150nm付近が輝度値が落ち込んでいるのは、他の材料と比べて特徴的です。

他にもポリプロピレンでは1540nm付近で明るくなっています。

さらに、各波長のピンポイントで見るのではなく、波長による輝度変化全体を捉えると、グラフの線の形状が材質により異なるので、材質の分類が可能になります。

 

実際の撮影風景と、分類の処理を行った様子がこちら↓

 

ハイパースペクトルカメラの原理、仕組み

一般的なカメラでも、エリアセンサ、ラインセンサがあるように、ハイパースペクトルカメラでも、エリアセンサのように撮影するタイプや、ラインセンサのように被写体を動かして撮影する必要のあるラインスキャン方式があり、さらに、光を分光する回折格子にも、反射型や透過型があるのですが、ここでは、ラインスキャン方式で、透過の回折格子を使うハイパースペクトルカメラの仕組みを紹介します。

まず最初に一般的なラインセンサカメラでは、どのように撮影しているかというと、被写体の像をレンズを介してラインセンサ上に結像させます。

この状態で、被写体を移動しながら連続的に撮影することで被写体全体の画像を取得しています。

では、ハイパースペクトルカメラでは、どのように撮影しているか?というと、上図のラインセンサの位置にエアスリット(細長い穴が開いたもの)を配置し、スリットを通り抜けた光をレンズで平行光にします。

その平行光を回折格子(グレーティング)に斜めに入射するように配置すると、回折格子から出た光は波長ごとに異なる角度で回折します。

この回折した光をレンズを介してエリアセンサ上に結像させます。

すると、エリアセンサ上では、縦方向に同じ位置の波長の異なる光の成分が結像した状態になります。

この状態で、通常のラインセンサと同じように、被写体を移動しながら撮影し、横1ラインごと(波長の異なるラインごと)に画像を並び替えると、1回のスキャンで複数波長で撮影した画像を同時に得ることができます。

実際の撮影に関して

ハイパースペクトルカメラを用いると、被写体の材質や状態によって、特定波長において特徴的な変化をする場合があると言いましたが、実際に撮影したい被写体において、そのような変化をするものか?というのは、実際に撮影してみないと分からない部分が多くあります。

具体的に撮影ワークを検討している方は、私の会社の営業までお問い合わせください。

下記、ページより電話か、製品に関してのお問い合わせフォームよりお願いします。

経験豊富な営業が対応してくれると思います。

被写体の撮影評価を行うことも可能です。

https://www.avaldata.co.jp/contact

 

関連製品

ハイパースペクトルカメラ AHS-003VIR (450nm~1700nm)

ハイパースペクトルカメラ AHS-U20MIR (1300nm~2150nm)

【OpenCV-Python】ヒストグラムの取得、表示

ここでは、ヒストグラムの取得方法と、取得したヒストグラムをmatplotlibで表示する方法を紹介したいと思います。

ヒストグラムの取得方法

OpenCVでヒストグラムを取得するには calcHist()関数を用います。

calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) ->hist
引数 説明
images 画像の配列を指定します。
cv2.split()関数でB, G, Rのカラープレーンに分離した3枚の画像なども指定できます。
channels ヒストグラムを取得する色のチャンネル(B, G, Rのどれか?)を指定します。
グレースケールの場合は [0]
B の場合は [0]
G の場合は [1]
R の場合は [2]
を指定します。
mask ヒストグラムを取得する領域のマスク画像を指定します。
画像全体のヒストグラムを取得する場合は None を指定します。
histSize ヒストグラムのビンの数を指定します。通常は[256]となります。
ranges ヒストグラムを取得する輝度値の範囲を指定します。 通常は[0, 256]です。
(戻り値)hist 指定したチャンネルのヒストグラムを取得します。

 

サンプルプログラム

import cv2

# 画像の読込
img = cv2.imread("Parrots.bmp",cv2.IMREAD_UNCHANGED)

if len(img.shape) == 3:
    # カラーのとき
    channels = 3
else:
    # モノクロのとき
    channels = 1

histogram = []
for ch in range(channels):
    # チャンネル(B, G, R)ごとのヒストグラム
    hist_ch = cv2.calcHist([img],[ch],None,[64],[0,256])
    histogram.append(hist_ch[:,0])# 次元を削除して追加

print("==== B ====")
print(histogram[0])
print("==== G ====")
print(histogram[1])
print("==== R ====")
print(histogram[2])

※今回は、ビンの数を64にしました。

 

実行結果

 

matplotlibでヒストグラムの表示

ヒストグラムの表示については、Pillowを使って、ヒストグラムの取得、表示する方法を行いました。

【Python/Pillow(PIL)】画像のヒストグラム取得、表示

Pillowでは色の順番がR, G, B の順ですが、 OpenCVは B, G, R の順なので、注意してください。

せっかくなので、ヒストグラムを取得する部分と、ヒストグラムを表示する部分は関数にしてみました。

 

import cv2
import matplotlib.pyplot as plt # ヒストグラム表示用

def get_histogram(img):
    '''ヒストグラムの取得'''
    if len(img.shape) == 3:
        # カラーのとき
        channels = 3
    else:
        # モノクロのとき
        channels = 1

    histogram = []
    for ch in range(channels):
        # チャンネル(B, G, R)ごとのヒストグラム
        hist_ch = cv2.calcHist([img],[ch],None,[256],[0,256])
        histogram.append(hist_ch[:,0])

    # チャンネルごとのヒストグラムを返す
    return histogram

def draw_histogram(hist):
    '''ヒストグラムをmatplotlibで表示'''
    # チャンネル数
    ch = len(hist)

    # グラフの表示色
    if (ch == 1):
        colors = ["black"]
        label = ["Gray"]
    else:
        colors = ["blue", "green", "red"]
        label = ["B", "G", "R"]

    # ヒストグラムをmatplotlibで表示
    x = range(256)
    for col in range(ch):
        y = hist[col]
        plt.plot(x, y, color = colors[col], label = label[col])

    # 凡例の表示
    plt.legend(loc=2)

    plt.show()

######################################################################

# 画像の読込
img = cv2.imread("Parrots.bmp",cv2.IMREAD_UNCHANGED)

# 画像の表示
cv2.imshow("Image", img)

# ヒストグラムの取得
hist = get_histogram(img)

# ヒストグラムの描画
draw_histogram(hist)

実行結果

関連記事

【Python/Pillow(PIL)】画像のヒストグラム取得、表示

【OpenCV/Python】画像ファイルの読み込み、表示

【OpenCV-Python】アフィン変換(同次座標系を使用)

アフィン変換については、こちら↓のページ

アフィン変換(平行移動、拡大縮小、回転、スキュー行列)

で、紹介していますが、回転や拡大縮小、平行移動などは3行3列の行列を使った同次座標系を用いるのが便利ですよ!

と言っているのですが、OpenCVでは、2行3列の行列を使ったアフィン変換となります。

アフィン変換では、平行移動だけ、回転移動だけ、拡大縮小だけ、などということも少なく、平行移動、回転、拡大縮小などのアフィン変換を組み合わせて、変換行列は行列の積で求めます。

しかしOpenCVで扱うアフィン変換は2行3列の行列なので、行列の積が計算できないので、個人的には少し不便に感じます。
特に平行移動がからむと、ちょっと難しくなります。

そこで、前半では標準的にOpenCVで出来る事を説明し、後半では3行3列の行列を使ったアフィン変換の方法を紹介したいと思います。

 

30°回転と0.8倍の縮小を行った例

import cv2
import affine

# 画像を読み込む
img = cv2.imread("image.bmp", cv2.IMREAD_UNCHANGED) 

height, width, _ = img.shape

# 回転行列の取得
affineMatrix = cv2.getRotationMatrix2D((width/2, height/2), 30, 0.8)
print(affineMatrix)

# アフィン変換
img = cv2.warpAffine(img, affineMatrix, (width, height))

# 画像の表示
cv2.imshow("Image", img)

# キー入力待ち(ここで画像が表示される)
cv2.waitKey()

実行結果

アフィン変換前 アフィン変換後

 

OpenCVによるアフィン変換

OpenCVでは2行3列の行列を指定して、画像をアフィン変換するwarpAffine()関数と、

回転の中心座標、回転角度、倍率を指定してアフィン変換行列(2行3列)を取得するgetRotationMatrix2D()関数、

変換前の3点の座標と、対応する変換後の3点の座標を指定してアフィン変換行列(2行3列)を取得するgetAffineTransform() 関数が用意されています。

 

warpAffine()

画像のアフィン変換を行います。

warpAffine( src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]] ) -> dst
引数 説明
src 変換前の画像データ
M 2行3列のアフィン変換行列
dsize 出力画像のサイズ (幅, 高さ)
dst borderMode = cv2.BORDER_TRANSPARENTのとき、背景画像を指定します。
ただし、dsizeとdstの画像サイズは同じにする必要があります。
flags 補間方法を指定します。
cv2.INTER_NEAREST
cv2.INTER_LINEAR
cv2.INTER_CUBIC
cv2.INTER_AREA
cv2.INTER_LANCZOS4
borderMode ボーダー(画像からはみ出した部分)の設定を行います。
cv2.BORDER_CONSTANT (初期値)
cv2.BORDER_REPLICATE
cv2.BORDER_REFLECT
cv2.BORDER_WRAP
cv2.BORDER_TRANSPARENT
borderValue borderModeにcv2.BORDER_CONSTANTを指定したときの画像のはみ出した部分の輝度値を指定します。 初期値:0
(戻り値)dst アフィン変換後の画像データ

 

補間モード(flag)について

cv2.INTER_NEAREST ニアレストネイバー
cv2.INTER_LINEAR バイリニア
cv2.INTER_CUBIC バイキュービック
cv2.INTER_AREA 縮小のときにモアレが発生しないモード
公式ドキュメントには拡大のときはINTER_NEARESTと同じと書いてありますが、実際にやってみると、INTER_LINEARと同じと思われます。
cv2.INTER_LANCZOS4 ランチョス

(元画像)目の部分を拡大したときの比較

INTER_NEAREST INTER_LINEAR INTER_CUBIC
INTER_AREA INTER_LANCZOS4

個人的な使い分けですが、画像処理結果を画像で見たいときはINTER_NEAREST

画像処理の画像データとして、拡大縮小したいときはINTER_LINEAR

写真のように見た目が大事なときはINTER_CUBIC

と、することが多いです。

(参考)

画素の補間(Nearest neighbor,Bilinear,Bicubic)の計算方法

 

borderMode(画像の外側の表示方法)について

cv2.BORDER_CONSTANT borderValueで指定した色で埋めます。(初期値は黒)
cv2.BORDER_REPLICATE 画像の一番外側の色で埋めます。
cv2.BORDER_REFLECT 画像を上下、左右方向にミラー反転して画像で繰り返し埋めます。
cv2.BORDER_WRAP 画像で繰り返し埋めます。
cv2.BORDER_TRANSPARENT dstに出力画像と同じ大きさの画像を指定すると、画像の外側は透過して、画像の上に画像を配置します。
BORDER_CONSTANT BORDER_REPLICATE BORDER_REFLECT
BORDER_WRAP BORDER_TRANSPARENT

 

getRotationMatrix2D()

基点(中心)周りに回転、拡大縮小を行うアフィン変換行列(2行3列)を取得します。

取得する行列は以下のようになります。

$$\begin{bmatrix}\alpha & \beta & (1-\alpha)\cdot center.x-\beta \cdot center.y \\-\beta & \alpha & \beta \cdot center.x + (1-\alpha )\cdot center.y \end{bmatrix}$$

ただし、

$$\begin{cases}\alpha=scale\cdot cos(angle)\\ \beta =scale\cdot sin(angle)\end{cases}$$

getRotationMatrix2D( center, angle, scale ) -> retval
引数 説明
center 回転、拡大縮小の基点(中心)となる(x,y)座標
angle 回転角度を度で指定します。 反時計周りが正
scale 拡大縮小する倍率を指定します。
(戻り値)retval (x,y)座標を基点に回転、拡大縮小したときの2行3列のアフィン変換行列を取得します。

 

getAffineTransform()

アフィン変換前の3点の座標と、それに対応したアフィン変換後の3点の座標を指定して、アフィン変換行列を求まます。

getPerspectiveTransform( src, dst) -> retval
引数 説明
src アフィン変換前の3点の(x,y)座標
dst アフィン変換前の点に対応したアフィン変換後の3点の(x,y)座標
(戻り値)retval 2行3列のアフィン変換行列

 

3行3列の行列を使ったアフィン変換

OpenCVでは、2行3列の行列を用いてアフィン変換を行うので、同次座標系の特徴でもある、平行移動も含めて行列の積でアフィン変換の行列を求めることができません。

そこで、回転、拡大縮小、平行移動の3行3列の行列は自作で作って、実際に画像をアフィン変換する部分はwarpAffine()関数のアフィン変換行列の部分に3行3列の行列をスライスして2行3列の行列として渡す方針でやってみたいと思います。

3行3列のアフィン変換行列を求める部分はファイル(affine.py)にまとめました。

# affine.py

import cv2
import numpy as np

def scaleMatrix(scale):
    '''拡大縮小用アフィン変換行列の取得(X方向とY方向同じ倍率)'''
    mat = identityMatrix() # 3x3の単位行列
    mat[0,0] = scale
    mat[1,1] = scale

    return mat

def scaleXYMatrix(sx, sy):
    '''拡大縮小用アフィン変換行列の取得(X方向とY方向の倍率をぞれぞれ指定)'''
    mat = identityMatrix() # 3x3の単位行列
    mat[0,0] = sx
    mat[1,1] = sy

    return mat

def translateMatrix(tx, ty):
    '''平行移動用アフィン変換行列の取得'''
    mat = identityMatrix() # 3x3の単位行列
    mat[0,2] = tx
    mat[1,2] = ty

    return mat

def rotateMatrix(deg):
    '''回転用アフィン変換行列の取得'''
    mat = identityMatrix() # 3x3の単位行列
    rad = np.deg2rad(deg) # 度をラジアンへ変換
    sin = np.sin(rad)
    cos = np.cos(rad)

    mat[0,0] = cos
    mat[0,1] = -sin
    mat[1,0] = sin
    mat[1,1] = cos

    return mat

def scaleAtMatrix(scale, cx, cy):
    '''点(cx, cy)を基点とした拡大縮小用アフィン変換行列の取得'''

    # 基点の座標を原点へ移動
    mat = translateMatrix(-cx, -cy)
    # 原点周りに拡大縮小
    mat = scaleMatrix(scale).dot(mat)
    # 元の位置へ戻す
    mat = translateMatrix(cx, cy).dot(mat)

    return mat

def rotateAtMatrix(deg, cx, cy):
    '''点(cx, cy)を基点とした回転用アフィン変換行列の取得'''

    # 基点の座標を原点へ移動
    mat = translateMatrix(-cx, -cy)
    # 原点周りに回転
    mat = rotateMatrix(deg).dot(mat)
    # 元の位置へ戻す
    mat = translateMatrix(cx, cy).dot(mat)

    return mat

def afiinePoint(mat, px, py):
    '''点(px, py)をアフィン変換行列(mat)で変換した後の点を取得'''

    srcPoint = np.array([px, py, 1])

    return mat.dot(srcPoint)[:2]

def inverse(mat):
    '''行列の逆行列を求める'''
    return np.linalg.inv(mat)

def identityMatrix():
    '''3x3の単位行列を取得'''
    return np.eye(3, dtype = np.float32) # 3x3の単位行列

使い方としては、上記のプログラムをaffine.pyというファイルに保存して、使う側のプログラムと同一フォルダに配置し、

import affine

のようにすれば、使えるようになります。

例えば、OpenCVのgetRotationMatrix2D()関数で行っていることは、

中心座標を原点へ平行移動

拡大縮小

回転(マイナス方向)

原点から中心へ平行移動

となっていて、この順番でアフィン変換の行列の積を行えば、行列が求まります。

getRotationMatrix2D()関数と同じアフィン変換行列を求めるサンプル

import cv2
import affine # affine.pyファイルを同一フォルダに置くこと

# 中心座標
cx = 100
cy = 5
# 回転角度
angle = 30
# 拡大縮小
scale = 0.8

# アフィン変換行列を求める
matAffine = affine.translateMatrix(-cx, -cy)                # 原点へ平行移動
matAffine = affine.scaleMatrix(scale).dot(matAffine)        # 拡大縮小
matAffine = affine.rotateMatrix(-angle).dot(matAffine)      # 回転
matAffine = affine.translateMatrix(cx, cy).dot(matAffine)   # 中心へ戻す
print(matAffine)
#[[ 0.6928203  0.4       28.717972 ]
# [-0.4        0.6928203 41.5359   ]
# [ 0.         0.         1.       ]]

matAffine_cv = cv2.getRotationMatrix2D((cx, cy), angle, scale)
print(matAffine_cv)
#[[ 0.69282032  0.4        28.7179677 ]
# [-0.4         0.69282032 41.53589838]]

あとは、ここで求めたアフィン変換の行列を2行3列の行列にスライスして、warpAffine()関数へ渡せば、画像のアフィン変換ができます。

img = cv2.warpAffine(img, affineMatrix[:2,], (width, height))

 

例題)3x3画素の画像を100倍に拡大する

画像を拡大するとき注意が必要なのが、画素の中心が、小数点以下が0になる座標(X.0, X.0)だという事に注意してください。詳しくは以下のページを参照ください。

画像の拡大

この事を知らずに、OpenCVのgetRotationMatrix2D()関数で3×3画素の市松模様の画像の拡大を行うと・・・

import numpy as np
import cv2

# 画像データ
img = np.array(
    [[0,   255,   0],
     [255,   0, 255],
     [0,   255,   0],
    ],
    dtype = np.uint8
    )

# OpenCVでアフィン変換行列を求める
matAffine = cv2.getRotationMatrix2D(center=(0,0), angle=0, scale=100)

# アフィン変換
img = cv2.warpAffine(img, matAffine, (300, 300), flags = cv2.INTER_NEAREST)

# 画像の表示
cv2.imshow("Image", img)

# キー入力待ち(ここで画像が表示される)
cv2.waitKey()

実行結果

上図のように左上の画素の中心に拡大されるため、ズレた画像になってしまいます。

この100倍の拡大を3行3列のアフィン変換を使って行うには、どのように考えるかというと、

(+0.5, +0.5)の平行移動(画像の角を原点に合わせる)

100倍の拡大

(-0.5, -0.5)の平行移動(左上の画素の中心を原点に合わせる)

 

というように変換を行います。

import numpy as np
import cv2
import affine # afiine.py のファイルが同一フォルダにあること

# 画像データ
img = np.array(
    [[0,   255,   0],
     [255,   0, 255],
     [0,   255,   0],
    ],
    dtype = np.uint8
    )

# OpenCVでアフィン変換行列を求める
matAffine = affine.translateMatrix(0.5, 0.5)            # 平行移動
matAffine = affine.scaleMatrix(100).dot(matAffine)      # 100倍の拡大
matAffine = affine.translateMatrix(-0.5, -0.5).dot(matAffine) # 原点の位置へ移動

# アフィン変換
img = cv2.warpAffine(img, matAffine[:2,], (300, 300), flags = cv2.INTER_NEAREST)

# 画像の表示
cv2.imshow("Image", img)

# キー入力待ち(ここで画像が表示される)
cv2.waitKey()

実行結果

このサンプルのソースコードはここ↓へ置きましたので、ご自由にお使いください。

OpenCVAffineSample.zip

 

関連記事

アフィン変換(平行移動、拡大縮小、回転、スキュー行列)

画像の拡大

画素の補間(Nearest neighbor,Bilinear,Bicubic)の計算方法

任意点周りの回転移動(アフィン変換)

【Python/NumPy】座標からアフィン変換行列を求める方法