地図のイラストを読み込み、ある座標(今回は53,463)とこの座標から一番遠い青色に塗られている建物を二値画像で表示するプログラムを作成しています。
プログラムを実行してみたところ、真っ黒になってしまいます。何かご教示いただければ幸いです。
以下プログラムです。
```C++
#include <iostream>
#include <opencv2/opencv.hpp>
#include <math.h>
#define FILE_NAME "../Debug/a.jpg"
//ウィンドウ名
#define WINDOW_NAME_INPUT "input"
#define WINDOW_NAME_OUTPUT "output"
int main(int argc, const char * argv[]){
double distance,dis_max=0; //画像の入力 cv::Mat src_img = cv::imread(FILE_NAME,cv::IMREAD_COLOR); cv::Vec3b val; if(src_img.empty()){//入力失敗の場合 fprintf(stderr,"Cannot read image file: %s,\n",FILE_NAME); return(-1); } //出力画像のメモリ確保 cv::Mat dst_img = cv::Mat(src_img.size(),CV_8UC1); //線形変換(入力画像、出力画像) for(int y=0;y<src_img.rows;y++){ for(int x=0;x<src_img.cols;x++){ //画素値の取得 val = src_img.at<cv::Vec3b>(y,x); if(val[0]>=220&&val[0]<=250&&val[1]>=210&&val[1]<=240&&val[2]>=190&&val[2]<=230){//青色の建物を探す distance=sqrt(((463-y)*(463-y))+((x-53)*(x-53)));//座標と建物の距離の計算 if(distance>dis_max){//一番遠い距離を探す dis_max=distance; } } } } //線形変換(入力画像、出力画像) for(int y=0;y<src_img.rows;y++){ for(int x=0;x<src_img.cols;x++){ //画素値の取得 val = src_img.at<cv::Vec3b>(y,x); if(val[0]>=220&&val[0]<=250&&val[1]>=210&&val[1]<=240&&val[2]>=190&&val[2]<=230){ distance=sqrt(((463-y)*(463-y))+((x-53)*(x-53))); if(distance==dis_max){//一番遠い距離と一致した場合 dst_img.at<unsigned char>(y,x)=255;//一番遠い青色の建物を表示 } } } } cv::imshow(WINDOW_NAME_INPUT,src_img); cv::imshow(WINDOW_NAME_OUTPUT,dst_img); cv::waitKey(); return 0;
}
追記↓ 皆様回答ありがとうございます。指摘されております「青色の建物」ですが実際には薄い水色のような色で、ツールを使いRGB値を調べていますのでこちらの値で問題はないです。説明不足で申し訳ございませんでした。 そして、皆様の回答を元にプログラムを全体的に書き直してみました。まだ理想の結果にはなっていません・・・ 引き続きご教示お願いいたします。 さらに追記↓ 編集で追加したプログラムをもう一度書き直してみましたがやはり結果が黒塗りになってしまい、行き詰まっています。 何かアドバイスお願いいたします。 ```C++ #include <iostream> #include <opencv2/opencv.hpp> #include <math.h> #define FILE_NAME "../Debug/a.jpg" //ウィンドウ名 #define WINDOW_NAME_INPUT "input" #define WINDOW_NAME_OUTPUT "output" int main(int argc, const char * argv[]){ double distance=0,dis_max=0; int max_x,max_y; int count = 0; float x_g = 0.0f; float y_g = 0.0f; //画像の入力 cv::Mat src_img = cv::imread(FILE_NAME); cv::Vec3b val; if(src_img.empty()){//入力失敗の場合 fprintf(stderr,"Cannot read image file: %s,\n",FILE_NAME); return(-1); } //出力画像のメモリ確保 cv::Mat dst_img = cv::Mat(src_img.size(),CV_8UC1); for(int y=0;y<src_img.rows;y++){ for(int x=0;x<src_img.cols;x++){ //画素値の取得 val = src_img.at<cv::Vec3b>(y,x); if(val[0]>=225&&val[0]<=245&&val[1]>=215&&val[1]<=235&&val[2]>=195&&val[2]<=220){//青色の建物を探す //重心の計算 count++; x_g += x; y_g += y; //重心の計算 cv::Point2f mc = cv::Point2f( x_g/count, y_g/count); distance=sqrt(((463-mc.y)*(463-mc.y))+((mc.x-53)*(mc.x-53)));//座標と建物の距離の計算 if(distance>dis_max){//一番遠い距離を探す dis_max=distance; max_x=x, max_y=y; } } } } printf("%f %d %d",dis_max,max_x,max_y);//確認用 for(int y=0;y<src_img.rows;y++){ for(int x=0;x<src_img.cols;x++){ val = src_img.at<cv::Vec3b>(y,x); if(val[0]>=225&&val[0]<=245&&val[1]>=215&&val[1]<=235&&val[2]>=195&&val[2]<=220){//青色の建物を探す count++; x_g += x; y_g += y; //重心の計算 cv::Point2f mc = cv::Point2f( x_g/count, y_g/count); distance=sqrt(((463-mc.y)*(463-mc.y))+((mc.x-53)*(mc.x-53)));//座標と建物の距離の計算 if(distance==dis_max){//一番遠い距離と一致した場合 dst_img.at<unsigned char>(y,x)=255;//一番遠い青色の建物を表示 } } } } cv::imshow(WINDOW_NAME_INPUT,src_img); cv::imshow(WINDOW_NAME_OUTPUT,dst_img); cv::waitKey(); return 0; }
1:コードは<code>を使いましょう
2:計算後、max_y,max_xの値がどうなっているのか、確認しましょう(コンソールに表示するなど)
3:距離計算等はいったんおいて、「元画像から、該当の色だけを白、それ以外を黒」といった二値化画像は作成できますか?
#元画像がわからないので妄想の域をでませんが、複数の候補の建物が白にぬられた画像になるのでしょう。
1 すみません、以後気をつけます。
2 max_x,max_yに値は入っていましたがおそらく間違っている(一番遠い建物の重心の座標ではない)と思います。
3 編集前のプログラムのif(distance==dis_max){//一番遠い距離と一致した場合 のif文を消去すると青い建物は白くなりそのほかは黒くなるので建物の色の抽出はできていると思われます。
dst_imgを生成するループを行う前に、count, x_g, y_gが再初期化されてませんけど、そこは問題ないですか?
確かに再初期化をしていませんでした。ご指摘ありがとうございます。
返信していただいた内容から考えると
thkanaさんが、最初に指摘されているとおり
「もっとも遠いとして計算された1点のみを白く塗っている」
だけじゃないでしょうか?
「一番遠いと判断された点を含む建物範囲を白くぬる」
といった処理がどこにも見当たりません
#「一点だけ白で、建物のほとんどは黒塗のまま」という質問なのか、
#「画像内が完全に真っ黒のまま」という質問なのか確認してなかったのだけれど
「一番遠いと判断された点を含む建物範囲を白くぬる」
については、fanaさんが描かれています
#それはそれとして、max_x,max_y方法はいいけど、それ以前のdoubleの値を==で比較するのは危険かな
回答5件
あなたの回答
tips
プレビュー