opencvの重心を求めるプログラムにopencvの関数ではない重心を求めるプログラムを入れたいです。

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 3,362

carnage0216

score 133

<実行した環境>

  • Windows10 64bit
  • visual studio 2017
  • opencv 3.4.1

opencvの重心を求めるプログラムにopencvの関数ではない重心を求めるプログラムを入れたいです。
ただ質問するだけではただの投げやりなどと言われて嫌な気分になるので私なりに調べてきました。

#include <stdio.h>
#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace cv;

int main(){

    Mat img = imread("sample.jpg", IMREAD_GRAYSCALE);

    Moments mu = moments( img, false );
    Point2f mc = Point2f( mu.m10/mu.m00 , mu.m01/mu.m00 );
    circle( img, mc, 4, Scalar(100), 2, 4);

    printf("x: %f  y: %f", mc.x, mc.y);

    imshow("img",img);
    waitKey(0);
    return 0;
}


以上のプログラムのmu.m10/mu.m00 , mu.m01/mu.m00の部分が重心を求める計算式であるとわかったので
この部分を以下の重心を求めるプログラムに置き換えたいのですが問題があります。

int count=0;
double x_g=0.0,y_g=0.0,x_d=0.0,y_d=0.0,xy_d=0.0
for(int y=0; y<height; y++){
for(int x=0;x<width; x++){
if(img_src[y*width+x] == 255){
count++;
x_g +=x;
y_g +=y;
}
}
}
x_g /=conut;
y_g/=count;

まず一つにMoments muのmuとPoint2f mcのmcが何を表しているか調べたのですがわかりませんでした。
また、Point2f( mu.m10/mu.m00 , mu.m01/mu.m00 ); と circle( img, mc, 4, Scalar(100), 2, 4);にmu、mcが入っていることからただ計算式を置き換えるだけでは意味がないと考えています。
しかし、どうやってmuとmcを考慮しながら計算式を置き換えてよいかわかりません。
どうか助言を頂けないでしょうか?
どうかよろしくお願いいたします。

<編集>
関数Point2fの使い方を調べようと本家の方で検索したのですが、例題としてPoint2f a(0.3f, 0.f), b(0.f, 0.4f);となり少なくともaとbの座標を二次元で表していることはわかるのですが、mcがなにを言っているのかわかりません。
調べたサイトはhttp://opencv.jp/opencv-2.1/cpp/basic_structures.htmlです。
できれば使い方のわからない関数がそのままの形で載っていればいいのですが、そうでない今回のような場合どのように調べればよいか教えていただけないでしょうか?

調べたサイトのようにPoint2f( m10/m00 , m01/m00 );と素直に座標だけ表せてくれればいいのですがなぜかmuが入ってPoint2f( mu.m10/mu.m00 , mu.m01/mu.m00 );となるので、どうやって座標のmuを考慮しながら計算のプログラムを入れるか悩みます。
多分muはPoint2f()より引数だと思うのですが、muが何を表しているのかわからず困り果てています。

編集6/10
<実行した環境>

  • Windows10 64bit
  • visual studio 2017
  • opencv 3.4.1

ベストアンサー後に申し訳ありません。asm様からのプログラムを読んで学習のために自分なりにプログラムを作りました。

以下のプログラムをVS2017でビルドしたところエラーが出ました。

#include <stdio.h>
#include <opencv/cv.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
using namespace cv;

int main() {

    Mat img = imread("sample.jpg", IMREAD_GRAYSCALE);

    int count = 0;
    int conut = 0;
    double x_g = 0.0, y_g = 0.0;
        for (int y = 0; y<height; y++) {
            for (int x = 0; x<width; x++) {
                if (img_src[y*width + x] == 255) {
                    count++;
                    x_g += x;
                    y_g += y;
                }
            }
        }
        int a;
        int b;
     a= x_g / conut;
     b= y_g / conut;

    Point2f mc = Point2f(a, b);//x_g / conutとy_g / conutをaとbと置いた。
    circle(img, mc, 4, Scalar(100), 2, 4);

    printf("x: %f  y: %f", mc.x, mc.y);

    imshow("img", img);
    waitKey(0);
    return 0;
}

こちらがエラーなのですが

1>------ ビルド開始: プロジェクト: Project18, 構成: Release x64 ------
1>Source.cpp
1>c:\users\daito\source\repos\project18\project18\source.cpp(16): error C2065: 'height': 定義されていない識別子です。
1>c:\users\daito\source\repos\project18\project18\source.cpp(17): error C2065: 'width': 定義されていない識別子です。
1>c:\users\daito\source\repos\project18\project18\source.cpp(18): error C2065: 'img_src': 定義されていない識別子です。
1>c:\users\daito\source\repos\project18\project18\source.cpp(18): error C2065: 'width': 定義されていない識別子です。
1>c:\users\daito\source\repos\project18\project18\source.cpp(30): warning C4244: '引数': 'double' から 'float' への変換です。データが失われる可能性があります。
1>プロジェクト "Project18.vcxproj" のビルドが終了しました -- 失敗。
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========


インクルードしたヘッダファイルにheight、width、img_srcの定義は書いてあると思ったのですが、エラーが出るということは必要なヘッダファイルが入っていないのだと思います。
変数height、widthと関数img_srcの定義が書いてあるgithubはないでしょうか?
ヘッダファイルでも構いません。
どうかよろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

回答 4

checkベストアンサー

+3

回答依頼来たので駄文ながら

調べたサイトのようにPoint2f( m10/m00 , m01/m00 );と素直に座標だけ表せてくれればいいのですがなぜかmuが入ってPoint2f( mu.m10/mu.m00 , mu.m01/mu.m00 );となるので、どうやって座標のmuを考慮しながら計算のプログラムを入れるか悩みます。

もしかして、C言語の構造体をご存知ないのでしょうか?

くっつけるだけならば単純に

#include <stdio.h>
#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace cv;

int main(){

    Mat img = imread("sample.jpg", IMREAD_GRAYSCALE);

    int count=0;
    double x_g=0.0,y_g=0.0;
    for(int y = 0 ; y < img.rows; y++){
        for(int x = 0 ; x < img.cols; x++){
            if(img.at<uchar>( y, x ) == 255){
                count++;
                x_g += x;
                y_g += y;
            }
        }
    }
    x_g /= conut;
    y_g /= count;

    Point2f mc = Point2f( x_g, y_g);

    circle( img, mc, 4, Scalar(100), 2, 4);

    printf("x: %f  y: %f", mc.x, mc.y);

    imshow("img",img);
    waitKey(0);
    return 0;
}

とするだけですよ
修正: 指摘を受け、img.at( y, x )をimg.at<uchar>( y, x )に変更


追記
Mat1b つまり Mat_<uchar>を使うと

#include <stdio.h>
#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace cv;

int main(){
    Mat1b img = imread("sample.jpg", IMREAD_GRAYSCALE);
    int count=0;
    double x_g=0.0,y_g=0.0;
    for(int y = 0, height = img.rows; y < height; y++){
        // パフォーマンス的には↓3行を置き換えた方が速い
        // const uchar *_img = img[y];
        // for(int x = 0, width = img.cols ; x < width; x++){ //変化なし
        //     if(_img[x] == 255){
        for(int x = 0, width = img.cols ; x < width; x++){
            if(img( y, x ) == 255){
                count++;
                x_g += x;
                y_g += y;
            }
        }
    }
    x_g /= conut;
    y_g /= count;

    Point2f mc = Point2f( x_g, y_g);

    circle( img, mc, 4, Scalar(100), 2, 4);

    printf("x: %f  y: %f", mc.x, mc.y);

    imshow("img",img);
    waitKey(0);
    return 0;
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/12 13:37 編集

    >>見つけたものを嬉しそうに見せびらかされても、私は貴方の飼い主ではないです。
    自分があほっぽく見えてきますね。あほなのですが。

    >>必要性も利点も感じません。
    どのように動いているのか知りたかっただけです。

    くだらないこだわりのせいでご迷惑おかけしました。
    どうもありがとうございます。

    キャンセル

  • 2018/06/12 14:33

    ちなみに、asmさんは必要性は別として、opencvとは別に
    画素のデータをいじるようなプログラムを作り、プログラムに打ち込んだりは出来るのでしょうか?(width,heightなどの定義、関数の自作など、めちゃくちゃ面倒なことが多いですが)
    僕には到底出来ない事ですが、asmさんほどの技術者ならば出来るのではないかと思い質問しました。

    キャンセル

  • 2018/06/12 14:54

    難しい事ではなく面倒なだけですね
    (読み込み形式を無圧縮bmp等に限り、画像の表示を行わなければ)

    キャンセル

+3

mc はモーメントmuから得られた重心
mu.m10 x方向の座標値の総和
mu.m01 y方向の座標値の総和
mu.m00 点の総数
重心は 座標値の平均なので (mu.m10/mu.m00, mu.m01/mu.m00)

...って書いてあった。

Moments muの各メンバ m00, m01, m10  については http://opencv.jp/opencv-2.1/cpp/structural_analysis_and_shape_descriptors.html?highlight=moment#moments  にきっちり書いてある。

muが何を表しているのかわからず困り果てています。

アナタそのmuを求めてるじゃん。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/08 02:29

    > ...のプログラムがあるため求めてるじゃんということでしょうか?

    じゃなかったらそのコードは何だというんです?

    キャンセル

  • 2018/06/08 09:30

    xとyの総数を画素の総数分を割り平均値(重心の座標)を求めるコードです。
    ごめんなさい。わかってはいたのですが、自信がなくてつい悩んでしまいました。

    キャンセル

  • 2018/06/08 09:33

    後は、このコードをopencvのプログラムと置き換えて動作させたいと思います。

    キャンセル

+2

こんなのがお望みか?

#include "opencv2/opencv.hpp"

int main(){
  using namespace cv;

  Mat img = imread("sample.jpg", IMREAD_GRAYSCALE);

  // unsigned char* img.data : 画像データの先頭
  // int            img.rows : 幅(pixel)
  // int            img.cols : 高さ(pixel)
  // size_t         img.step : 一行のbyte数
  int   count = 0;
  float x_g = 0.0f;
  float y_g = 0.0f;
  for ( int y = 0; y < img.rows; y++ ) {
    for ( int x = 0; x < img.cols; x++ ) {
      if ( img.data[y*img.step + x] == 255 ) {
        count++;
        x_g += x;
        y_g += y;
      }
    }
  }
  Point2f mc = Point2f( x_g/count, y_g/count);

  circle( img, mc, 4, Scalar(100), 2, 4);

  imshow("img",img);
  waitKey(0);
}

!実行結果

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/12 20:33

    感謝します。いつもいつもご迷惑おかけします。
    身近にepistemeさんのような先生が居たらどんなにいいことかと思ってしまいます。
    本当にどうもありがとうございます。早速ビルドしてみます。

    キャンセル

  • 2018/06/12 21:49

    ちなみにどうたってimg_src[y*whide + x]からimg.data[y*img.step + x]を作ったのですか?
    というかimg.dataとimg.stepをどうやって見つけてきたのですか?

    キャンセル

  • 2018/06/13 03:49

    あらかたマニュアルに書いてある。

    キャンセル

+1

    int conut = 0;
    double x_g = 0.0, y_g = 0.0;
    for (int y = 0; y<height; y++) {
        for (int x = 0; x<width; x++) {
            if (img_src[y*width + x] == 255) {
                count++;
                x_g += x;
                y_g += y;
            }
        }
    }
    int a;
    int b;
    a= x_g / conut;
    b= y_g / conut;

自分なりに書いたのはココ↑なんでしょ?
自分で書いたコードなら width, height, img_src が何を意味するのかわかってるハズね? 

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/10 23:36

    asmさんのプログラムは実行できたのですが、どうしても、
    for (int y = 0; y<height; y++) {
    for (int x = 0; x<width; x++) {
    if (img_src[y*width + x] == 255)
    の方でもビルドしたいと思ったためです。いくつかの方法で実行できないかと思ったためです。
    要は欲張りなのです。

    キャンセル

  • 2018/06/11 03:38

    > インクルードしたヘッダファイルにheight、width、img_srcの定義は書いてあると思ったのですが

    これはナゼ?

    キャンセル

  • 2018/06/11 20:31

    参考にしたサイトでは
    #include <stdio.h>
    #include "opencv/cv.h"
    #include "opencv/highgui.h"ヘッダファイルをインクルードしてエラーが出なかったためです。
    しかし、今思うとそのサイトではimg_srcを使っていないので私の勘違いでした。

    キャンセル

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

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる
  • トップ
  • C++に関する質問
  • opencvの重心を求めるプログラムにopencvの関数ではない重心を求めるプログラムを入れたいです。