OpenCV。 Androidの輪郭解析を使用して道路標識を検索する

こんにちはHabr!



交通標識検索アルゴリズムの独自の実装を共有したいと思います。



なぜ輪郭解析なのか?



輪郭解析の干渉に対する耐性はやや弱いですが、単純さと速度により、このアプローチを非常にうまく適用できました。





ただし、実際には、Androidプラットフォームで必要な係数の検索を実装することは非常に困難であることが判明しました(OpenCVウィジェットを使用しようとはせず、代わりに画面をフレームに分割しました。設定は左側にあり、背面カメラからのビデオストリームは右側にあります)。 UIおよびプロジェクトロジックの特定の実装は、以下のリンクから入手できます。



交通標識を検索する一連の操作は次のとおりです。





実際の状況ではうまく機能するとは言えません(おそらく、検出アルゴリズムは最適ではありませんが、最も使いやすいと判明しました)。 また、最適な係数を見つけるのは困難です(私の都市では道路標識の「狩り」がたくさんありました。日焼けした標識に出会ったこともあり、それらにはまったく赤がありませんでした)。



しかし、単純さは目を楽しませてくれるので、たとえばロボット工学などで輪郭解析の用途を見つけることは非常に可能です。



AndroidでOpenCVを使用した経験に関する追加の利点:



カメラの画像が上下逆になっている場合は回転させます
 extern "C" JNIEXPORT void JNICALL Java_ru_dksta_prohibitingsigndetector_ActivityMain_rotation(JNIEnv /* *env */, jclass /* activity */, jlong matAddress, jint angle) { CV_Assert(angle % 90 == 0 && angle <= 360 && angle >= -360); cv::Mat* mat = (cv::Mat*) matAddress; if (angle == 180 || angle == -180) { cv::flip(*mat, *mat, -1); } }
      
      







ソルト&ペッパーノイズの実装
 extern "C" JNIEXPORT void JNICALL Java_ru_dksta_prohibitingsigndetector_ActivityMain_saltPepperNoise(JNIEnv /* *env */, jclass /* activity */, jlong matAddress) { cv::Mat* mat = (cv::Mat*) matAddress; cv::Mat noise = cv::Mat::zeros((*mat).rows, (*mat).cols, CV_8U); cv::randu(noise, 0, 255); cv::Mat black = noise < 30; cv::Mat white = noise > 225; (*mat).setTo(255, white); (*mat).setTo(0, black); }
      
      







「ピクチャーインピクチャー」モードで処理するカメラのビデオを表示する
 if (secondView) { cv::Mat miniView = colorDilated.clone(); cv::cvtColor(miniView, miniView, cv::COLOR_GRAY2RGB); cv::resize(miniView, miniView, cv::Size(), 0.6, 0.6, cv::INTER_LINEAR); cv::Size miniSize = miniView.size(); cv::Size maxSize = original.size(); int startY = maxSize.height - miniSize.height; for (int y = startY; y < maxSize.height; y++) { for (int x = 0; x < miniSize.width; x++) { (*(cv::Mat*)matAddress).at<cv::Vec3b>(cv::Point(x, y)) = miniView.at<cv::Vec3b>(cv::Point(x, y - startY)); } } }
      
      







OpenCVでテキストを書く
 cv::Mat* mat = (cv::Mat*)matAddress; int textStartY = TEXT_LINE_HEIGHT; std::ostringstream output; output << std::setw(2) << std::setfill('0') << fpsCount << " FPS"; cv::putText(*mat, output.str(), cv::Point(TEXT_START_X, textStartY), FONT_FACE, FONT_SCALE, GREEN, TEXT_THICKNESS); output.seekp(0); textStartY += TEXT_LINE_HEIGHT; cv::putText(*mat, getLayerTypeDesc(layerType), cv::Point(TEXT_START_X, textStartY), FONT_FACE, FONT_SCALE, GREEN, TEXT_THICKNESS);
      
      







プロジェクトへのリンク



All Articles