Python : 画像の極座標変換 warpPolar

Opencvを使った、画像の極座標変換についてです。

またまた久々の更新です。

最近は不動産投資をするための準備で貯金がどんどん減っていく状態(TT)。。。

これ以外にも今いる会社が業績不振で黒字リストラをしているので

(会社は再構築といっていますが)

全体的に気分があまりよくなく、

後ろ向きなことばかり考えてしまっているこの頃です。

※今回は幸いなことにリストラ対象ではないのですが、何時対象になることやら・・・

 

それで本題ですが、極座標変換についてですが、

仕事で扱う製品は丸いものなのですが、今外観検査のプログラム検討をしていて、

丸を極座標にしたらどうなるかな~と思って調べてやり方がある程度分かったので、

載せておきます。

 

この月の画像を使います(検索して出てきたフリー画像です)

f:id:Kangkang1981:20200906143628j:plain



丸い画像を極座標変換する方法です。

まず変換フラグを作ります。

 キュービック補間 + 外れ値塗りつぶし + 極座標へリニアマッピング
flags = cv2.INTER_CUBIC + cv2.WARP_FILL_OUTLIERS + cv2.WARP_POLAR_LINEAR

引き数:画像, 変換後サイズ(幅、高さ)、中心座標(X座標、Y座標)、半径、変換フラグ
linear_polar = cv2.warpPolar(frame_trim, (w, h), (int(h/2), int(w/2)), int(radius+10), flags)

linear_polar = cv2.warpPolar(画像, (幅, 高さ), (中心座標x,y), 半径, flags)

左が極座標変換前、右が変換後です。

f:id:Kangkang1981:20200906142927j:plain

 

逆変換

極座標変換にフラグの部分に逆変換の部分の「cv2.WARP_INVERSE_MAP」を追加します。

flags = cv2.INTER_CUBIC + cv2.WARP_FILL_OUTLIERS + cv2.WARP_POLAR_LINEAR + cv2.WARP_INVERSE_MAP
linear_polar_inverse = cv2.warpPolar(linear_polar, (w, h),(int(h/2), int(w/2)), int(radius+10), flags)

左が変換前、右が逆変換後

f:id:Kangkang1981:20200906142939j:plain

 

極座標変換をする際の中心座標と半径は元の位置になるので、

あらかじめ知る必要があります。

このため、下記のプログラムは画像を読み込んだ後、

最小外接円を元に画像を切り出した後に極座標変換及び、逆変換をしています。

最小外接円等については下記の記事を参照ください。

kangkang1981.hatenablog.com

 

単純に極座標変換だけを書いたほうがわかりやすかったと思いますが、

変換する前に中心を取っておく必要があるので、ちょっと長めになっています。

 

プログラム詳細は下記になります。

 

#モジュールのインポート
import cv2

#画像を読み込む
frame = cv2.imread('moon.jpg')

"""
画像の中心がほしいので、contoursで検出、最小外接円で中心座標の抜き取り
"""
#gray画像を作成
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#二極化
ret2,th = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

cimg = th

contours, hierarchy = cv2.findContours(cimg,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

for i, cnt in enumerate(contours):
        # 輪郭の面積を計算する。
        area = cv2.contourArea(cnt)
        # 抽出する範囲を指定
        if area > 100 and area < 100000:
            #frme画像に書き込む
            #cv2.drawContours(frame, contours, i, (0,0,255), 5)
            #インデックスNoと面積を確認
            (x,y),radius = cv2.minEnclosingCircle(cnt)

#この画像で極座標変換をします。
frame_trim = frame[int(y-radius-10):int(y+radius+10),int(x-radius-10):int(x+radius+10)]

"""
切り取った画像のサイズ取得(cのチャンネル数はここでは不要)
"""
h,w,c = frame_trim.shape print('h : '+str(h)) print('w : '+str(w)) """ 円→極座標 """ # キュービック補間 + 外れ値塗りつぶし + 極座標へリニアマッピング flags = cv2.INTER_CUBIC + cv2.WARP_FILL_OUTLIERS + cv2.WARP_POLAR_LINEAR # 引き数:画像, 変換後サイズ(幅、高さ)、中心座標(X座標、Y座標)、半径、変換フラグ linear_polar = cv2.warpPolar(frame_trim, (w, h), (int(h/2), int(w/2)), int(radius+10), flags) """ 逆変換 極座標 → 円 """ flags = cv2.INTER_CUBIC + cv2.WARP_FILL_OUTLIERS + cv2.WARP_POLAR_LINEAR + cv2.WARP_INVERSE_MAP linear_polar_inverse = cv2.warpPolar(linear_polar, (w, h),(int(h/2), int(w/2)), int(radius+10), flags) """ 写真の合成、横に並べる """ frame_h = cv2.hconcat([frame_trim,linear_polar]) frame_h2 = cv2.hconcat([linear_polar,linear_polar_inverse]) """ 画像の表示 & 書き込み """ cv2.imshow('trim',frame_trim) cv2.imshow('linear',frame_h) cv2.imshow('linear_inverse',frame_h2) cv2.imwrite('moon_trim.jpg',frame_trim) cv2.imwrite('linear.jpg',frame_h) cv2.imwrite('linear_inverse.jpg',frame_h2) cv2.waitKey(0) cv2.destroyAllWindows()

今までにpythonについて書いた記事はここにリンクを貼ってあります。

興味があればぜひご覧ください。