3

カメラで撮影した写真から単一のオブジェクトを抽出しようとしています。オブジェクトのないカメラのビューの画像が存在します。カメラの焦点は変わりませんが、オブジェクトが表示されているときの照明は変わります。オブジェクトはしっかりしていますが、一定の灰色ではありません。これは、右側の参照画像と左側のオブジェクトを含む別の画像の写真です。写真はモノクロです。

すべての処理は画像取得後に行われ、計算時間は大きな問題ではありません。アルゴリズムの精度はより重要です。

ここで見つけたほとんどの質問は、2 つの写真が似ているかどうかという問題を扱っていますが、その後の測定のために、画像内でオブジェクトが占める領域を見つけることに興味があります。

これまでのところ、ぼやけた画像をしきい値で減算してから 2 値化するさまざまな組み合わせを試しましたが、これは照明不変ではありません。事前に参照画像に相対的な照明の違いを掛けても、満足のいく結果は得られません。別の露出をシミュレートするためのより良い方法が使用されれば、うまくいくかもしれません。

また、Log フィルター処理された画像といくつかの大まかな近隣ピクセル比較を差し引いてみましたが、成功しませんでした。

ある種の記述子比較で処理できるはずの非常に直感的なタスクのように感じますが、良い解決策を見つけるのに苦労しています。私が見逃していた良い方法を知っている人はいますか?

前もって感謝します。


Franco Callari の回答のおかげで、既製の OpenCV 関数ではカバーされていないヒストグラム マッチングに出くわしました。これはよくある問題のように思えるので、誰かがそれを使いたい場合に備えて、私の非効率的なハックアップをここに投稿することもできます.

// Aligns the histogram of the source image to match that of the target image. 
// Both are evaluated in a ROI, not across the whole picture.
// The function assumes 8-bit grayscale images.
static void alignHistogram(Mat alignsource, const Mat& aligntarget, 
    const int rowstart = 500, const int rowend = 700, 
    const int colstart = 0, const int colend = 1000)    
{   
    // 1) Calculate target and source histogram in region of interest
    // 2) Compute the integral of each histogram (cumulative distribution function)
    // 3) Set brightness of each pixel in the source image to the brightness of the target where the CDF values are equal

    Mat ROIsource = alignsource(Range(rowstart, rowend), Range(colstart, colend));
    Mat ROItarget = aligntarget(Range(rowstart, rowend), Range(colstart, colend));
    MatND hist_source, hist_target;

    int bins = 256, int histSize[] = {bins};
    float sranges[] = { 0, 256 };        const float* ranges[] = { sranges };
    int channels[] = {0};
    calcHist( &ROItarget, 1, channels, Mat(), hist_target, 1, histSize, ranges, true, false );
    calcHist( &ROItarget, 1, channels, Mat(), hist_source, 1, histSize, ranges, true, false );

    Mat CDF_target_2d, CDF_source_2d; 
    integral(hist_target, CDF_target_2d);
    integral(hist_source, CDF_source_2d);
    Mat CDF_target = CDF_target_2d.col(1),  CDF_source = CDF_source_2d.col(1);

    // Cycle through source image inefficiently and adjust brightness
    for (int i = 0; i < alignsource.rows; i++)
    {
        for (int j = 0; j < alignsource.cols; j++)
        {
            int source_brightness = alignsource.at<unsigned char>(i, j);
            double cdf_source_value = CDF_source.at<double>(source_brightness);

            int target_brightness = 0;
            while (target_brightness < 256) {
                if (CDF_target.at<double>(target_brightness) > cdf_source_value)
                    break;
                target_brightness++;
            }
            alignsource.at<unsigned char>(i, j) = target_brightness;
        }
    }
}

照明を調整すると、オブジェクトの最初の推測を改善するのに役立ちますが、正確な輪郭を取得するには十分ではありません。特に、背景がオブジェクトとあまり変わらない場合や特徴が豊富な場合はそうです。一瞬。

4

5 に答える 5

3

カメラが移動されておらず、背景が変更されていない場合 (サンプル写真から見えるように)、グローバル イルミネーションの違いは、(ほとんどの場合) 2 つの要因のいずれかによる可能性があります。被写体がシーン内にある場合の絞り値または露出時間、または露出時間ウィンドウ内の時間変化する光源 (ランプ内の 60Hz ライン ハムなど)。後者は、イルミネーターがストロボの場合は除外されます (ストロボが再充電するのに十分なショット間の時間が与えられます)。

上記で「大部分」と言ったのは、被写体がフレームの大部分を占めているため、そこから反射された光がグローバル イルミネーションにも影響するためですが、あなたの場合、これはおそらく 2 次効果です。

最善のアプローチは、キャ​​プチャをより適切に制御することです。少なくとも、カメラの自動露出を無効にし、バラスト ライトを使用します (ストロボでない場合)。

できない場合 (または追加) は、イコライゼーションではなく、グローバル ヒストグラム アライメントから開始する必要があります。他のポスターで示唆されているように、グローバルなヒストグラムの均等化は、被写体のピクセル値が背景だけでなくヒストグラムの一部になるため、害を及ぼす可能性があります. ただし、カメラが移動していない場合は、背景であることがわかっている画像フレーム領域で事前に識別し、「背景のみ」と「被写体あり」の両方の画像で、それらからのみヒストグラムをサンプリングできます。次に、たとえばダイナミック レンジの上下 5% の値を見つけ、それらが一致するようにグローバル スケーリングを適用します。

于 2013-03-28T14:13:34.867 に答える
1

1) ヒストグラム均等化 (OpenCV の cvEqualizeHist() 関数) を使用します。照明の違いを解消するのに役立ちます。

2) 2 つのほぼ同一の画像が得られます (オブジェクトのない画像とオブジェクトのある画像。カメラは静止しているため、他の部分は同一でなければなりません)。それらの違いを機能別に見てみましょう

void cvSub(
    const CvArr* src1,
    const CvArr* src2,
    CvArr*       dst,
    const CvArr* mask  = NULL)

3) 結果は次のようになります: オブジェクトが配置されている場所はほぼ白になり、画像の残りの部分はそれほど明るくありません。使用する

void cvInRangeS(
    const CvArr* src,
    CvScalar     lower,
    CvScalar     upper,
    CvArr*       dst
);

この関数を使用して、画像内のピクセルが特定の指定範囲内にあるかどうかを確認できます。したがって、白に近い範囲を取ります (たとえば (200, 255))。

4) で画像に残っているオブジェクトのエッジを見つけます

int cvFindContours(
  IplImage*              img,
  CvMemStorage*          storage,
  CvSeq**                firstContour,
  int                    headerSize  = sizeof(CvContour),
  CvContourRetrievalMode mode        = CV_RETR_LIST,
  CvChainApproxMethod    method      = CV_CHAIN_APPROX_SIMPLE
);
于 2013-03-28T08:21:39.800 に答える
0

私はから始めます:

(i) ヒストグラムの均等化 (ii) 2 つの画像の減算 (参照オブジェクトの位置が実際に変わらない場合) (iii) 開口部 (侵食、膨張)、異なるマスク サイズ (3x3、5x5) を試す

次に、結果の画像を見てください。「ゴミ」がどれだけ残っているか。関心のある領域の外側に接続されたピクセルが多すぎる場合は、開口部のマスクを増やす必要がある場合があります (または浸食のみ)。画像を 2 値化し、バイナリをマスクとして取得して、元の対象領域を除外することができます。

于 2013-03-28T09:08:21.450 に答える
0

もう 1 つのオプションは、バックグラウンド減算アルゴリズムを使用することです。主にビデオ シーケンスに使用されますが、問題ないはずです。opencvのCode Book Methodをお勧めします

  1. codebook メソッドに入力画像を与えます
  2. コードブック メソッドにバックグラウンドとして取り込まなければならないフレーム数を伝える変数があります。この場合、これは 1 つになります。
  3. その結果、フォアグラウンド イメージとバックグラウンド イメージが作成されます。
  4. その後、スムージングを使用してノイズを取り除くことができます。
  5. オブジェクトを含む必要がある前景画像を使用します(指が見つけたいものであると仮定します)
  6. opencv メソッドを使用して輪郭を見つけます。

お役に立てれば

于 2013-04-01T12:15:22.330 に答える
0

イルミネーションが時変の場合、HSV または HSI 空間の色相情報を利用できます。色相はイルミネーションに対して強く不変であることが証明される場合があります。画像がグレースケールの場合は、ヒストグラムの均等化を試すことができます

于 2013-03-28T06:02:25.580 に答える