opencvを使って、読み込んだ画像の中心を変形の中心としたせん断変形を行うプログラムを作成したいのですが、自分が調べた限りではわかりませんでした。
opencvを使うのは初めてなので関数等もあまり把握できていませんが、考え方だけでもいいのでご教授願いたいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
まずは「アフィン変換 OpenCV」とかで検索してみては.
OpenCVの関数名を記しておきます.
getAffineTransform
: 3点の対応から 2x3 の変換マトリクスが得られます.warpAffine
: 2x3 の変換マトリクスを用いて画像を変換します.
[追記]
とりあえず,ある座標の位置が変わらないような変形をするコードを書いてみました.
参考になれば.
C++
1int main() 2{ 3 const cv::Point TopLeft( 105, 55 ); 4 const cv::Point BottomRight( 256, 178 ); 5 const cv::Point Center = ( TopLeft + BottomRight ) * 0.5; //※変換の中心 6 7 cv::Mat Img( 240, 320 ,CV_8UC3 ); 8 {//※元画像に,何かてきとーに「中心」がわかるような描画 9 Img = cv::Scalar( 96, 0, 0 ); 10 cv::rectangle( Img, TopLeft, BottomRight, cv::Scalar(0,0,255) ); 11 12 const cv::Point TopRight( BottomRight.x, TopLeft.y ); 13 const cv::Point BottomLeft( TopLeft.x, BottomRight.y ); 14 cv::line( Img, TopLeft, BottomRight, cv::Scalar(0,0,255) ); 15 cv::line( Img, BottomLeft, TopRight, cv::Scalar(0,0,255) ); 16 17 cv::circle( Img, Center, 6, cv::Scalar( 0,255,255 ), 1 ); 18 cv::circle( Img, Center, 40, cv::Scalar( 0,255,0 ), 3 ); 19 } 20 cv::imshow( "Img", Img ); 21 22 //変換マトリクスを作る 23 cv::Matx<float,2,3> M = 0; 24 { 25 //てきとーに「せん断」になる感じの値 26 M(0,0) = 1; M(1,1)=1; //左側2x2部分対角は1 27 M(0,1) = 0.25; //せん断の成分(1) 28 M(1,0) = 0.5; //せん断の成分(2) 29 //Centerの位置が変わらないような並進成分を求めてマトリクスにセット 30 cv::Vec2f TransedCenter = M * cv::Vec3f( (float)Center.x, (float)Center.y, 1.0f ); 31 M(0,2) = ( Center.x - TransedCenter(0) ); 32 M(1,2) = ( Center.y - TransedCenter(1) ); 33 } 34 35 //マトリクスMでアフィン変換 36 cv::Mat ResultImg; 37 cv::warpAffine( Img, ResultImg, M, cv::Size(Img.cols, Img.rows) ); 38 cv::imshow( "Affine", ResultImg ); 39 40 //元画像と重ねて表示してみる 41 cv::addWeighted( Img, 0.5, ResultImg, 0.5, 0, ResultImg ); 42 cv::imshow( "Result", ResultImg ); 43 44 // 45 if( cv::waitKey() == 's' ) 46 { 47 cv::imwrite( "Img.png", Img ); 48 cv::imwrite( "Result.png", ResultImg ); 49 } 50 return 0; 51}
変換前の画像 Img
の表示結果:
(「ある座標」の位置がわかるような適当な図形が描画されている)
アフィン変換結果と変換前画像を重ねてみた表示結果:
(描画した図形の真ん中が一致している)
※上記コードの //Centerの位置が変わらないような並進成分を求めてマトリクスにセット
のところを,(このマトリクスの内容を前提として)手計算した結果で書くならば,
C++
1M(0,2) = -Center.y * M(0,1); 2M(1,2) = -Center.x * M(1,0);
となりますが,汎用性を考えれば(?) 上記コードのように「中心」を変換した座標から並進量を求めるので良いかと(そこに圧倒的な計算時間を要するとかいうこともないでしょうから).
投稿2021/12/06 04:05
編集2021/12/07 07:20総合スコア11996
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/12/06 04:14
2021/12/06 04:17
2021/12/06 04:24
2021/12/06 04:28
2021/12/07 07:00
0
自己解決
自分の理解不足で申し訳ございません。
出力画像にせん断変形した画像が収まるようにしたかったのですが、縮小や平行移動で解決できそうです。
みなさまからの回答は理解を深めるためゆっくりと読ませていただきます。
詳しい説明等ありがとうございました。
投稿2021/12/09 03:13
総合スコア6
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
「画像の中心を変形の中心としたせん断変形」という意味を理解できていないかもしれませんが、サンプルを書いてみました。
import numpy as np import cv2 from matplotlib import pyplot as plt #画像読み込み img = cv2.imread('./sample_data/input.jpg') h,w,_ = img.shape print(h,w) # 横方向に20画素分せん断させる場合 shear_x_pix = 20 # 元画像の変形前の座標を4か所指定 p_original = np.float32([ [0, 0], # 元画像の左上点 [w, 0], # 元画像の右上点 [0, h], # 元画像の左下点 [w, h]] # 元画像の右下点 ) # 元画像の上記4点を変形によってどの座標に移動させるのかを座標で指定(これも4点) p_trans = np.float32([ [shear_x_pix, 0], # 左上点の移動先 [w + shear_x_pix, 0], # 右上点の移動先 [0, h], # 左下点の移動先(このケースでは移動しない) [w, h]] # 右下点の移動先(このケースでは移動しない) ) # 変換マトリクスと射影変換 M = cv2.getPerspectiveTransform(p_original, p_trans) # 変形後の画像サイズ out_size = (w + shear_x_pix, h) out = cv2.warpPerspective(img, M, out_size) print(out.shape) plt.imshow(cv2.cvtColor(out, cv2.COLOR_BGR2RGB))
参考画像の幾何変換
投稿2021/12/06 08:28
総合スコア59
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。