opencvを用いて読み込んだ画像の回転を行っています。
以下のプログラムで画像の回転を行い実行できたのですが、
画像が回転し、元の画像の場所が黒く表示されるのが気に入りません。
表示するウィンドウごと回転することは出来ないのでしょうか?
この画像の黒い部分をなくすように
ウインドウを表示するということです。
回転した画像と同じだけ回転させたウインドウを表示するようなことです。
回転した画像にマッチングを行いたいと考えているのですが、、、
使用環境は、VC++2010Express、opencv2.4.9です。
よろしくお願いします。
#define SCALE 0.8 // 画像の拡大率
int main( int argc, char **argv ) {
char windowNameSource[] = "Source"; // 元画像を表示するウィンドウの名前
char windowNameDestination[] = "Destination"; // 変換後の画像を表示するウィンドウの名前
// 画像を読み込む
IplImage *sourceImage = cvLoadImage( "image/lena.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR );
if ( sourceImage == NULL ){
// 画像が見つからなかった場合
printf( "画像が見つかりません\n" );
return -1;
}
// 画像を生成する
IplImage *destinationImage = cvCreateImage( cvGetSize( sourceImage ), IPL_DEPTH_8U, 3 ); // 変換後の画像用IplImage
CvPoint2D32f center = cvPoint2D32f( sourceImage->width / 2.0, sourceImage->height / 2.0); //回転中心
// 行列を生成する
CvMat *rotationMatrix = cvCreateMat( 2, 3, CV_32FC1 ); // 回転行列
// 変換行列を求める
cv2DRotationMatrix( center, ANGLE, SCALE, rotationMatrix);
// 画像の拡大、縮小、回転を行う
cvWarpAffine( sourceImage, destinationImage, rotationMatrix, CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS, cvScalarAll( 0 ) );
// ウィンドウを生成する
cvNamedWindow( windowNameSource, CV_WINDOW_AUTOSIZE );
cvNamedWindow( windowNameDestination, CV_WINDOW_AUTOSIZE );
// 画像を表示する
cvShowImage( windowNameSource, sourceImage );
cvShowImage( windowNameDestination, destinationImage );
// キー入力を待つ
cvWaitKey( 0 );
// 画像を保存する
cvSaveImage( "image/destination.bmp", destinationImage );
// メモリを解放する
cvReleaseImage( &sourceImage );
cvReleaseImage( &destinationImage );
// ウィンドウを破棄する
cvDestroyWindow( windowNameSource );
cvDestroyWindow( windowNameDestination );
return 0;
}
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
0
こんにちは。
普通のウィンドウは辺が水平・垂直のものだけですが、斜めの辺のウィンドウを表示したいということでしょうか?
もし、そうであればOpenCVはサポートしていない筈です。
Windows APIで任意形状のウィンドウ表示はできます。すぐには出てこないのですが、昔実装したことがあります。
.NETを使えば簡単にできるようなので、UI部をC++/CLIで実装することも考えられると思います。
でも、どちらがたいへんか微妙です。任意形状のウィンドウ表示も多少面倒ですが、C++/CLIを新たに使いはじめることと大差ないような気がします。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
.NETを使えば簡単にできるようなので...
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
ウィンドウを回転させることはWindowsにその機能が搭載されていないのでできませんが、ウィンドウの枠や背景を表示させずに斜めの画像だけを表示させることならできます。
その方法は三つあります。
- 画像に合わせたリージョンをウィンドウに設定し、画像部分だけを表示
- レイヤードウィンドウのカラーキーによる画像部分以外の透明化
- レイヤードウィンドウのアルファチャンネルによる画像部分以外の透明化
1はSetWindowRgn
関数、2と3はレイヤードウィンドウに設定した上でSetLayeredWindowAttributes
関数とUpdateLayeredWindow
関数で、比較的簡単に実現可能です。
ただし、OpenCVのウィンドウ表示機能では細かい制御ができないので、自前でウィンドウを作成/表示させないと無理かもしれません。
追記
カラーキーを指定して、その色の部分を透過させるウィンドウの実装例です。画像ファイルのパスや背景のサイズは適当に調整してください。
#include "opencv2\opencv.hpp"
#include <windows.h>
#include <atlbase.h>
#include <atlwin.h>
// cv::waitKeyの自前実装版
static int sKey = 0;
int myWaitKey(int iWaitTime)
{
ULONGLONG timeup = ::GetTickCount64() + iWaitTime;
do
{
MSG msg;
while(::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT)
return -1;
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
} while(sKey == 0 && (iWaitTime == 0 || ::GetTickCount64() < timeup));
int key = sKey;
sKey = 0;
return key;
}
// カラーキーを使った透過ウィンドウの実装例
class ColorKeyWindow : public ATL::CWindowImpl<ColorKeyWindow>
{
cv::Mat mImage;
public:
DECLARE_WND_CLASS(L"ColorKeyWindow-Class");
// コンストラクタでウィンドウを作成し、カラーキーを設定
ColorKeyWindow(const wchar_t * iName, COLORREF iColorKey = RGB(0,0,255))
{
RECT rc = {0, 0, 0, 0};
HWND hwnd = this->Create(nullptr, rc, iName, WS_POPUP, WS_EX_LAYERED);
::SetLayeredWindowAttributes(hwnd, iColorKey, 0, LWA_COLORKEY);
}
// デストラクタでウィンドウ破棄
~ColorKeyWindow()
{
this->DestroyWindow();
}
// 画像表示
void ShowImage(const cv::Mat & iMat)
{
mImage = iMat.clone();
this->SetWindowPos(nullptr, 0, 0, mImage.cols, mImage.rows, SWP_NOMOVE|SWP_NOZORDER|SWP_SHOWWINDOW);
// 実際にはWM_PAINTで表示
this->Invalidate(FALSE);
}
private:
BEGIN_MSG_MAP(HelloWindow)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
MESSAGE_HANDLER(WM_CHAR, OnChar)
END_MSG_MAP()
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(&ps);
if(!mImage.empty())
{
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = mImage.cols;
bmi.bmiHeader.biHeight = -mImage.rows;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = mImage.channels() * 8;
bmi.bmiHeader.biClrImportant = BI_RGB;
::SetDIBitsToDevice(hdc, 0, 0, mImage.cols, mImage.rows, 0, 0, 0, mImage.rows, mImage.ptr(0), &bmi, DIB_RGB_COLORS);
}
EndPaint(&ps);
return 0;
}
LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// ウィンドウをマウスで移動できるようにする
return HTCAPTION;
}
LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
sKey = (int)wParam;
return 0;
}
};
// サンプルプログラム
int main(int argc, char* argv[])
{
cv::Mat image = cv::imread("lena.jpg");
cv::Mat bgimage(cv::Size(800, 800), CV_8UC3);
ColorKeyWindow window(L"MyWindow");
int angle = 0;
while(1)
{
bgimage = cv::Scalar(255, 0, 0); // ブルーバックでクリア
cv::Point2d center(image.cols / 2, image.rows / 2);
cv::Mat mat = cv::getRotationMatrix2D(center, angle, 1.0);
mat.at<double>(0, 2) += (bgimage.cols - image.cols) / 2;
mat.at<double>(1, 2) += (bgimage.rows - image.rows) / 2;
cv::warpAffine(image, bgimage, mat, bgimage.size(), cv::INTER_LINEAR, cv::BORDER_TRANSPARENT);
angle = (angle + 360 - 1) % 360;
window.ShowImage(bgimage);
int key = myWaitKey(1);
if(key == '\x1b')
break;
}
return 0;
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/07/12 21:31
回転した画像と同じだけ回転したウインドウを表示したいということです。
2016/07/12 22:04
従って、回転したかのように見えるウィンドウを表示するしかないです。
そのためには、黒い部分をウィンドウ領域でないように指定することになります。
catsforepawさんが書かれてますが、SetWindowRgn()を使えば可能です。(他の方法は使ったことないので私は良く分かりません。)
「ウィンドウの形状を変更してみる」(http://chokuto.ifdef.jp/urawaza/windowrgn.html)に解説がありました。このサイトでは楕円や星形のウィンドウを表示してますが、それらの代わりに回転した矩形のウィンドウを表示することになります。
また、「.NETを使えば簡単にできる」のリンク先に、epistemeさんが示したサンプルのようなウィンドウを表示する方法が解説されてます。
2016/07/12 22:08
この意味が良く分かりません。
画像マッチングは表示とは無関係と思います。回転していてもしてなくても、更には表示してなくてもテンプレート・マッチングのような処理は、(当たり前ですが)可能です。
具体例を書いて頂けると理解しやすいかも知れません。
2016/07/12 23:36
具体的に書きますと、入力画像を用意し、テンプレートの角度を変えながら
テンプレートマッチングを行いたいと考えています。
現状では、テンプレートの角度を変えると、ウィンドウ内に黒い領域が現れ
正確なマッチングを行えません。
この問題を解決したいと考えています。
2016/07/12 23:52
ということは、ウィンドウ表示の話は無関係ですね。
そのような時は、テンプレートの元画像を少し広い範囲で回転させ、周囲の黒い部分を避けて「まっすぐな」矩形を取り出し、テンプレート画像とするのが良いと思います。
テンプレート・マッチング処理側で斜めのテンプレート画像に対応することも考えられますが、大きく速度が落ちそうですし、OpenCVのテンプレート・マッチングは斜めのテンプレート画像に対応してなかったと思います。
2016/07/13 08:17
2016/07/13 11:42
あまりよくわからないので、簡単なプログラムを教えていただくことは
できないでしょうか?
2016/07/13 11:49