私は OpenCV が初めてで、画像内のオブジェクトの数を数えようとしています。MATLAB Image Processing Toolbox を使用する前にこれを行い、OpenCV (Android) でも同じアプローチを採用しました。
最初のステップは、画像をグレースケールに変換することでした。次に、しきい値を設定してから、ブロブの数を数えます。Matlab には、"bwlabel" というコマンドがあり、ブロブの数が表示されます。私はOpenCVでそのようなことを見つけることができませんでした(繰り返しますが、私はOpenCVとAndroidの初心者です)。
ここに私のコードがあります、
//JPG to Bitmap to MAT
Bitmap i = BitmapFactory.decodeFile(imgPath + "mms.jpg");
Bitmap bmpImg = i.copy(Bitmap.Config.ARGB_8888, false);
Mat srcMat = new Mat ( bmpImg.getHeight(), bmpImg.getWidth(), CvType.CV_8UC3);
Utils.bitmapToMat(bmpImg, srcMat);
//convert to gray scale and save image
Mat gray = new Mat(srcMat.size(), CvType.CV_8UC1);
Imgproc.cvtColor(srcMat, gray, Imgproc.COLOR_RGB2GRAY,4);
//write bitmap
Boolean bool = Highgui.imwrite(imgPath + "gray.jpg", gray);
//thresholding
Mat threshed = new Mat(bmpImg.getWidth(),bmpImg.getHeight(), CvType.CV_8UC1);
Imgproc.adaptiveThreshold(gray, threshed, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 75, 5);//15, 8 were original tests. Casey was 75,10
Core.bitwise_not(threshed, threshed);
Utils.matToBitmap(threshed, bmpImg);
//write bitmap
bool = Highgui.imwrite(imgPath + "threshed.jpg", threshed);
Toast.makeText(this, "Thresholded image saved!", Toast.LENGTH_SHORT).show();
次のステップでは、拡張と侵食を使用して穴と文字を埋めようとしましたが、ブロブが互いにくっついてしまい、最終的には間違ったカウントになります。膨張と侵食のパラメーターを調整する際に、穴を埋めることとブロブを互いに付着させることの間にはトレードオフがあります。
ここにコードがあります、
//morphological operations
//dilation
Mat dilated = new Mat(bmpImg.getWidth(),bmpImg.getHeight(), CvType.CV_8UC1);
Imgproc.dilate(threshed, dilated, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new org.opencv.core.Size (16, 16)));
Utils.matToBitmap(dilated, bmpImg);
//write bitmap
bool = Highgui.imwrite(imgPath + "dilated.jpg", dilated);
Toast.makeText(this, "Dilated image saved!", Toast.LENGTH_SHORT).show();
//erosion
Mat eroded = new Mat(bmpImg.getWidth(),bmpImg.getHeight(), CvType.CV_8UC1);
Imgproc.erode(dilated, eroded, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new org.opencv.core.Size(15, 15)));
Utils.matToBitmap(eroded, bmpImg);
//write bitmap
bool = Highgui.imwrite(imgPath + "eroded.jpg", eroded);
Toast.makeText(this, "Eroded image saved!", Toast.LENGTH_SHORT).show();
時々私のM&Mが隣り合っているかもしれないからです!;)
Hough Circles も使用しようとしましたが、結果は非常に信頼できません (実際のコインだけでなく、コインの画像でもテストされています)。
ここにコードがあります、
//hough circles
Mat circles = new Mat();
// parameters
int iCannyUpperThreshold = 100;
int iMinRadius = 20;
int iMaxRadius = 400;
int iAccumulator = 100;
Imgproc.HoughCircles(gray, circles, Imgproc.CV_HOUGH_GRADIENT,
1.0, gray.rows() / 8, iCannyUpperThreshold, iAccumulator,
iMinRadius, iMaxRadius);
// draw
if (circles.cols() > 0)
{
Toast.makeText(this, "Coins : " +circles.cols() , Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(this, "No coins found", Toast.LENGTH_LONG).show();
}
このアプローチの問題は、アルゴリズムが完全な円のみに制限されていることです(AFAIK)。そのため、机の上にある M&M やコインをスキャンしてカウントしようとすると、うまく機能しません (デバイスの角度が変わるため)。このアプローチでは、時々、ノーが少なくなります。検出されたコインの数と、時にはそれ以上の数 (なぜそれ以上なのかわかりません??)。
この画像をスキャンすると、アプリは 19 コインを表示することもあれば、38 コインをカウントすることもあります...円として検出される可能性のある他の機能があることは知っていますが、なぜ 38 なのかまったくわかりません..?
だから私の質問...
- 隣接するブロブを結合せずに穴を埋めるより良い方法はありますか?
- オブジェクトの数を正確にカウントするにはどうすればよいですか? HoughCircles アプローチでサークルのみをカウントするようにアプリを制限したくありません。
参考までに: OpenCV-2.4.9-android-sdk. 私もOpenCVとAndroidの初心者であることを心に留めておいてください。
どんな助けでも大歓迎です。
ありがとう&乾杯!
ジャイナム