この記事は、OpenCVライブラリの使用を開始したばかりで、その機能のすべてをまだ知らない初心者に役立ちます。 特に、OpenCVライブラリのbioにヒントを得たモジュールに基づいて、照明用のモーション適応検出器を作成することができます。 この動き検出器は、通常の2フレームの減算よりも薄明かりで動作します。
網膜について少し
OpenCVライブラリーにはRetinaクラスが含まれており、Retinaクラスには、網膜モデルの2つの情報チャネル(小細胞経路と大細胞経路)の時空間フィルターがあります。 私たちは、実際にはすでに動き検出器であるマグノセルラーチャネルに興味があります:動きがある画像領域の座標を取得するためだけに残っており、動き検出器が静止画像を表示した場合に発生する干渉に何らかの形で応答しません。
画像に動きがない場合のマグノチャネルの出力でのノイズ
コード
まず、バイオにヒントを得たモジュールを接続して初期化する必要があります。 この例では、モジュールは色を使用せずに機能するように構成されています。
モジュールの接続と初期化
#include "opencv2/bioinspired.hpp" // cv::Ptr<cv::bioinspired::Retina> cvRetina; // // void initRetina(cv::Mat* inputFrame) { cvRetina = cv::bioinspired::createRetina( inputFrame->size(), // false, // : cv::bioinspired::RETINA_COLOR_DIAGONAL, // false, // 1.0, // . 10.0); // // cvRetina->write("RetinaDefaultParameters.xml"); // cvRetina->setup("RetinaDefaultParameters.xml"); // cvRetina->clearBuffers(); }
デフォルト設定は* RetinaDefaultParameters.xml *ファイルに保存されます。 おそらくそれを修正するのが理にかなっています。
RetinaDefaultParameters
私自身のために、いくつかのパラメーター(ColorModeおよびamacrinCellsTemporalCutFrequency)を変更しました。 以下は、magno出力のいくつかのパラメーターの説明の翻訳です。
normaliseOutput-出力が0〜255の範囲でスケーリングするか(true)否か(false)を決定します
ColorMode- (true)処理に色を使用するか、(false)グレー画像を処理するかを決定します。
光受容体LocalAdaptationSensitivity-光受容体の感度(0から1)。
光受容体 TemporalConstant-光受容体の1次のローパスフィルターの時定数。高い時間周波数(ノイズまたは高速移動)を減らすために使用する必要があります。 フレームのブロックが使用されます。一般的な値は1フレームです。
光受容体SpatialConstantは、 光受容体の1次のローパスフィルターの空間定数です。 これを使用して、高い空間周波数(ノイズまたは太い輪郭)を減らすことができます。 ピクセルのブロックが使用され、一般的な値は1ピクセルです。
horizontalCellsGain-セルの水平ネットワークの強化。 値が0の場合、出力信号の平均値はゼロです。 パラメーターが1に近い場合、明るさはフィルターされず、出力でまだ達成可能です。 通常の値は0です。
HcellsTemporalConstant-水平セルの1次ローパスフィルター時定数。 このアイテムは、低時間周波数(局所的な輝度変動)をカットするために必要です。 フレームのブロックが使用されます。一般的な値は1フレームです。
HcellsSpatialConstant-水平セルの1次のローパスフィルターの空間定数。 低空間周波数(ローカル輝度)をカットするために使用する必要があります。 ピクセルのブロックが使用され、一般的な値は5ピクセルです。
ganglionCellsSensitivity-神経節細胞適応の局所出力の圧縮力。最良の結果を得るには、0.6〜1の範囲の値を設定します。 値は感度の低下に応じて増加します。 そして、出力はより速く飽和します。 推奨値は0.7です。
<?xml version="1.0"?> <opencv_storage> <OPLandIPLparvo> <colorMode>0</colorMode> <normaliseOutput>1</normaliseOutput> <photoreceptorsLocalAdaptationSensitivity>0.89e-001</photoreceptorsLocalAdaptationSensitivity> <photoreceptorsTemporalConstant>5.0000000000000000e-001</photoreceptorsTemporalConstant> <photoreceptorsSpatialConstant>1.2999997138977051e-001</photoreceptorsSpatialConstant> <horizontalCellsGain>0.3</horizontalCellsGain> <hcellsTemporalConstant>1.</hcellsTemporalConstant> <hcellsSpatialConstant>7.</hcellsSpatialConstant> <ganglionCellsSensitivity>0.89e-001</ganglionCellsSensitivity></OPLandIPLparvo> <IPLmagno> <normaliseOutput>1</normaliseOutput> <parasolCells_beta>0.1</parasolCells_beta> <parasolCells_tau>0.1</parasolCells_tau> <parasolCells_k>7.</parasolCells_k> <amacrinCellsTemporalCutFrequency>1.2000000476837158e+000</amacrinCellsTemporalCutFrequency> <V0CompressionParameter>5.4999998807907104e-001</V0CompressionParameter> <localAdaptintegration_tau>0.</localAdaptintegration_tau> <localAdaptintegration_k>7.</localAdaptintegration_k></IPLmagno> </opencv_storage>
私自身のために、いくつかのパラメーター(ColorModeおよびamacrinCellsTemporalCutFrequency)を変更しました。 以下は、magno出力のいくつかのパラメーターの説明の翻訳です。
normaliseOutput-出力が0〜255の範囲でスケーリングするか(true)否か(false)を決定します
ColorMode- (true)処理に色を使用するか、(false)グレー画像を処理するかを決定します。
光受容体LocalAdaptationSensitivity-光受容体の感度(0から1)。
光受容体 TemporalConstant-光受容体の1次のローパスフィルターの時定数。高い時間周波数(ノイズまたは高速移動)を減らすために使用する必要があります。 フレームのブロックが使用されます。一般的な値は1フレームです。
光受容体SpatialConstantは、 光受容体の1次のローパスフィルターの空間定数です。 これを使用して、高い空間周波数(ノイズまたは太い輪郭)を減らすことができます。 ピクセルのブロックが使用され、一般的な値は1ピクセルです。
horizontalCellsGain-セルの水平ネットワークの強化。 値が0の場合、出力信号の平均値はゼロです。 パラメーターが1に近い場合、明るさはフィルターされず、出力でまだ達成可能です。 通常の値は0です。
HcellsTemporalConstant-水平セルの1次ローパスフィルター時定数。 このアイテムは、低時間周波数(局所的な輝度変動)をカットするために必要です。 フレームのブロックが使用されます。一般的な値は1フレームです。
HcellsSpatialConstant-水平セルの1次のローパスフィルターの空間定数。 低空間周波数(ローカル輝度)をカットするために使用する必要があります。 ピクセルのブロックが使用され、一般的な値は5ピクセルです。
ganglionCellsSensitivity-神経節細胞適応の局所出力の圧縮力。最良の結果を得るには、0.6〜1の範囲の値を設定します。 値は感度の低下に応じて増加します。 そして、出力はより速く飽和します。 推奨値は0.7です。
計算を高速化するには、* cv :: resize *関数を使用して最初に着信画像を縮小するのが理にかなっています。 干渉の存在を判断するには、平均画像の明るさまたはエントロピーの値を使用できます。 また、プロジェクトの1つで、特定の輝度レベルの上下のピクセルカウントを使用しました。 境界ボックスは、輪郭検索機能を使用して取得できます。 ネタバレの下には動き検出器のコードがあり、これは動作するふりをせず、おおよその可能な実装を示しているだけです。
動き検出器コード
// #define CV_MOTION_DETECTOR_MEDIAN_FILTER_N 512 // static float meanBuffer[CV_MOTION_DETECTOR_MEDIAN_FILTER_N]; static float entropyBuffer[CV_MOTION_DETECTOR_MEDIAN_FILTER_N]; // static int numFrame = 0; // float getMedianArrayf(float* data, unsigned long nData); // // inputFrame - RGB CV_8UC3 // arrayBB - void updateMotionDetector(cv::Mat* inputFrame,std::vector<cv::Rect2f>& arrayBB) { cv::Mat retinaOutputMagno; // magno cv::Mat imgTemp; // float medianEntropy, medianMean; // cvRetina->run(*inputFrame); // cvRetina->getMagno(retinaOutputMagno); // , cv::imshow("retinaOutputMagno", retinaOutputMagno); // , if (numFrame < CV_MOTION_DETECTOR_MEDIAN_FILTER_N) { numFrame++; } // float mean = cv::mean(retinaOutputMagno)[0]; // float entropy = calcEntropy(&retinaOutputMagno); // if (numFrame >= 2) { // // // for (i = numFrame - 1; i > 0; i--) { entropyBuffer[i] = entropyBuffer[i - 1]; } entropyBuffer[0] = entropy; // // // for (i = numFrame - 1; i > 0; i--) { meanBuffer[i] = meanBuffer[i - 1]; } meanBuffer[0] = mean; // medianEntropy = getMedianArrayf(entropyBuffer, numFrame); medianMean = getMedianArrayf(meanBuffer, numFrame); } else { medianEntropy = entropy; medianMean = mean; } // , , // if (medianMean >= mean) { // , , if ((medianEntropy * 0.85) >= entropy) { // // , // // cv::threshold(retinaOutputMagno, imgTemp,150, 255.0, CV_THRESH_BINARY); // cv::threshold(retinaOutputMagno, imgTemp,150, 255.0, CV_THRESH_BINARY); // std::vector<std::vector<cv::Point>> contours; cv::findContours(imgTemp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); if (contours.size() > 0) { // arrayBB.resize(contours.size()); // float xMax, yMax; float xMin, yMin; for (unsigned long i = 0; i < contours.size(); i++) { xMax = yMax = 0; xMin = yMin = imgTemp.cols; for (unsigned long z = 0; z < contours[i].size(); z++) { if (xMax < contours[i][z].x) { xMax = contours[i][z].x; } if (yMax < contours[i][z].y) { yMax = contours[i][z].y; } if (xMin > contours[i][z].x) { xMin = contours[i][z].x; } if (yMin > contours[i][z].y) { yMin = contours[i][z].y; } } arrayBB[i].x = xMin; arrayBB[i].y = yMin; arrayBB[i].width = xMax - xMin ; arrayBB[i].height = yMax - yMin; } } else { arrayBB.clear(); } } else { arrayBB.clear(); } // retinaOutputMagno.release(); imgTemp.release(); } // template<typename aData> void quickSort(aData* a, long l, long r) { long i = l, j = r; aData temp, p; p = a[ l + (r - l)/2 ]; do { while ( a[i] < p ) i++; while ( a[j] > p ) j--; if (i <= j) { temp = a[i]; a[i] = a[j]; a[j] = temp; i++; j--; } } while ( i<=j ); if ( i < r ) quickSort(a, i, r); if ( l < j ) quickSort(a, l , j); }; // float getMedianArrayf(float* data, unsigned long nData) { float medianData; float mData[nData]; register unsigned long i; if (nData == 0) return 0; if (nData == 1) { medianData = data[0]; return medianData; } for (i = 0; i != nData; ++i) { mData[i] = data[i]; } quickSort(mData, 0, nData - 1); medianData = mData[nData >> 1]; return medianData; };
動き検出器の例。