質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

5回答

919閲覧

座標から距離を求め二値化する

seriko

総合スコア29

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2020/07/28 13:30

編集2020/07/30 02:03

地図のイラストを読み込み、ある座標(今回は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; }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yominet

2020/07/29 09:14

1:コードは<code>を使いましょう 2:計算後、max_y,max_xの値がどうなっているのか、確認しましょう(コンソールに表示するなど) 3:距離計算等はいったんおいて、「元画像から、該当の色だけを白、それ以外を黒」といった二値化画像は作成できますか? #元画像がわからないので妄想の域をでませんが、複数の候補の建物が白にぬられた画像になるのでしょう。
seriko

2020/07/29 13:04

1 すみません、以後気をつけます。 2 max_x,max_yに値は入っていましたがおそらく間違っている(一番遠い建物の重心の座標ではない)と思います。 3 編集前のプログラムのif(distance==dis_max){//一番遠い距離と一致した場合 のif文を消去すると青い建物は白くなりそのほかは黒くなるので建物の色の抽出はできていると思われます。
hytNInE

2020/07/30 02:47

dst_imgを生成するループを行う前に、count, x_g, y_gが再初期化されてませんけど、そこは問題ないですか?
seriko

2020/07/30 06:14

確かに再初期化をしていませんでした。ご指摘ありがとうございます。
yominet

2020/07/30 16:32

返信していただいた内容から考えると thkanaさんが、最初に指摘されているとおり 「もっとも遠いとして計算された1点のみを白く塗っている」 だけじゃないでしょうか? 「一番遠いと判断された点を含む建物範囲を白くぬる」 といった処理がどこにも見当たりません #「一点だけ白で、建物のほとんどは黒塗のまま」という質問なのか、 #「画像内が完全に真っ黒のまま」という質問なのか確認してなかったのだけれど
yominet

2020/07/30 16:37

「一番遠いと判断された点を含む建物範囲を白くぬる」 については、fanaさんが描かれています #それはそれとして、max_x,max_y方法はいいけど、それ以前のdoubleの値を==で比較するのは危険かな
guest

回答5

0

自己解決

バウンディングボックスで座標を計算し、建物の輪郭塗りつぶしでできました。

投稿2020/08/02 14:05

seriko

総合スコア29

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

他回答で指摘されていますが,「青色」の判定の妥当性をまずは担保してください.
その判定では,「かなり白に近い明るい画素」を見つける判定になっているように見えます.
(一般的に「青」と聞いて思い浮かべる色はその範囲に入らないと思います.)
一度,何らかのペイントソフトなりで対象画像の対象領域の画素値を調べてみて,その結果から閾値を定めるのが手っ取り早いと思います.

また,やりたいことは,(面積を持った)領域を表示することであろうと思うので,(画素単位ではなく)「領域毎に」扱うべきに思います.
e.g.

  1. 「青い部分」マスク画像を作る
  2. マスク画像から領域群を抽出,領域毎の代表座標(重心とかでいいのかな?)を決める
  3. 領域毎に,ある座標(今回は53,463)と前記代表座標との距離を求め,最も遠い領域を見つける
  4. 3.で見つけた領域だけを残したマスクを生成し,これを結果とする.

といった処理手順になるかと.

投稿2020/07/29 04:16

fana

総合スコア11708

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

とりあえず、青色の建物を探すの判定に当てはまる座標をコンソールにでも出力してみてはいかがでしょうか?
座標が合っているのであれば、画像出力の問題だし、合っていないのであれば、青色の建物を探す判定の問題となります。よくわからない場合は、課題を切り分けるのが良いと思います。

あと、青色の判定はRGBでやるよりHSVに変換してからの方が良さそうな気がします。
こちらのページを参考にしてみてはいかがでしょう?

投稿2020/07/29 03:55

hytNInE

総合スコア133

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ドット一つが白になっているだけなので見落としている、とかそういうことはないでしょうか?

余計なこと。
・val[0]>=220&&val[0]<=250&&val[1]>=210&&val[1]<=240&&val[2]>=190&&val[2]<=230 って青色なのかなぁ?
・最大距離を求めた時にx,yを記録しておけば2度めのループは回さなくてもいいですよね。

int max_x=-1,max_y=-1;//一応無効な値で初期化しておく //線形変換(入力画像、出力画像)<-このコメントは違うだろう 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; max_x=x;//追加 max_y=y; } } } }

投稿2020/07/28 23:39

thkana

総合スコア7659

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

seriko

2020/07/29 01:46

回答ありがとうございます。 dst_img.at<unsigned char>(max_y,max_x)=255;ということですかね?確かにこれなら二回ループを回す必要はありませんでしたね。しかし、いずれにしても出力画像が真っ黒になってしまい正常な結果が得られるずにいます・・・
guest

0

dst_img.at<unsigned char>(y,x)=255;//一番遠い青色の建物を表示

黒く塗ってるからでは?

投稿2020/07/28 13:45

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問