#opencv #image-processing #object-detection #opencv4android
#opencv #обработка изображений #обнаружение объекта #opencv4android
Вопрос:
Я использую OpenCV4Android версии 2.4.11 и пытаюсь обнаружить прямоугольники в кадрах, полученных с камеры. Я ссылался на некоторые вопросы на этом веб-сайте, и они были очень полезны. но проблема, с которой я сталкиваюсь в настоящее время, заключается в том, что когда я пытаюсь обнаружить объект со светлым цветом посередине, как показано на исходном изображении ниже, алгоритм обнаружения в этом случае не обнаруживает объект целиком, скорее он обнаруживает его темные части, как показано на рисунке в разделе под названием «обработано» ниже.
в размещенном ниже коде указаны шаги, которым я следовал, и пороговые значения, которые я использовал для обнаружения объектов во фреймах.
пожалуйста, дайте мне знать, почему объект в целом не обнаруживается и что я могу сделать, чтобы обнаружить весь объект, а не только его части
код:
//step 1
this.mMatGray = new Mat();
Imgproc.cvtColor(this.mMatInputFrame, this.mMatGray, Imgproc.COLOR_BGR2GRAY);
//step 2
this.mMatEdges = new Mat();
Imgproc.blur(this.mMatGray, this.mMatEdges, new Size(7, 7));//7,7
//step 3
Imgproc.Canny(this.mMatEdges, this.mMatEdges, 128, 128*2, 5, true);//..,..,2,900,7,true
//step 4
dilated = new Mat();
Mat dilateElement = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE, new Size(3, 3));
Imgproc.dilate(mMatEdges, dilated, dilateElement);
ArrayList<MatOfPoint> contours = new ArrayList<>();
hierachy = new Mat();
Imgproc.findContours(dilated, contours, hierachy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint2f approxCurve = new MatOfPoint2f();
if (contours.size() > 0) {
for (int i = 0; i < contours.size(); i ) {
MatOfPoint2f contour2f = new MatOfPoint2f(contours.get(i).toArray());
double approxDistance = Imgproc.arcLength(contour2f, true) * .02;//.02
Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);
MatOfPoint points = new MatOfPoint(approxCurve.toArray());
if (points.total() >= 4 amp;amp; Imgproc.isContourConvex(points) amp;amp; Math.abs(Imgproc.contourArea(points)) >= 40000 amp;amp; Math.abs(Imgproc.contourArea(points)) <= 150000) {
Rect boundingRect = Imgproc.boundingRect(points);
RotatedRect minAreaRect = Imgproc.minAreaRect(contour2f);
Point[] rectPoints = new Point[4];
minAreaRect.points(rectPoints);
Rect minAreaAsRect = minAreaRect.boundingRect();
//to draw the minAreaRect
for( int j = 0; j < 4; j ) {
Core.line(mMatInputFrame, rectPoints[j], rectPoints[(j 1)%4], new Scalar(255,0,0));
}
Core.putText(mMatInputFrame, "MinAreaRect", new Point(10, 30), 1,1 , new Scalar(255,0,0),2);
Core.putText(mMatInputFrame, "Width: " minAreaAsRect.width , new Point(minAreaAsRect.tl().x, minAreaAsRect.tl().y-100), 1,1 , new Scalar(255,0,0),2);
Core.putText(mMatInputFrame, "Height: " minAreaAsRect.height, new Point(minAreaAsRect.tl().x, minAreaAsRect.tl().y-80), 1,1 , new Scalar(255,0,0),2);
Core.putText(mMatInputFrame, "Area: " minAreaAsRect.area(), new Point(minAreaAsRect.tl().x, minAreaAsRect.tl().y-60), 1,1 , new Scalar(255,0,0),2);
//drawing the contour
Imgproc.drawContours(mMatInputFrame, contours, i, new Scalar(0,0,0),2);
//drawing the boundingRect
Core.rectangle(mMatInputFrame, boundingRect.tl(), boundingRect.br(), new Scalar(0, 255, 0), 1, 1, 0);
Core.putText(mMatInputFrame, "BoundingRect", new Point(10, 60), 1,1 , new Scalar(0,255,0),2);
Core.putText(mMatInputFrame, "Width: " boundingRect.width , new Point(boundingRect.br().x-100, boundingRect.tl().y-100), 1,1 , new Scalar(0,255,0),2);
Core.putText(mMatInputFrame, "Height: " boundingRect.height, new Point(boundingRect.br().x-100, boundingRect.tl().y-80), 1,1 , new Scalar(0,255,0),2);
Core.putText(mMatInputFrame, "Area: " Imgproc.contourArea(points), new Point(boundingRect.br().x-100, boundingRect.tl().y-60), 1,1 , new Scalar(0,255,0),2);
}
}
}
исходное изображение:
обработанное изображение:
Ответ №1:
Я реализовал на c . API одинаковы, поэтому вы можете легко портировать для Android. Я использовал Opencv 2.4.8
. Пожалуйста, проверьте реализацию. Надеюсь, код говорит, что сделано:
#include <iostream>
#include <string>
#include "opencv/highgui.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
using namespace std;
using namespace cv;
Mat GetKernel(int erosion_size)
{
Mat element = getStructuringElement(cv::MORPH_CROSS,
cv::Size(2 * erosion_size 1, 2 * erosion_size 1),
cv::Point(erosion_size, erosion_size) );
return element;
}
int main()
{
Mat img = imread("C:/Users/dell2/Desktop/j6B3A.png",0);//loading gray scale image
Mat imgC = imread("C:/Users/dell2/Desktop/j6B3A.png",1);
GaussianBlur(img,img,Size(7,7),1.5,1.5);
Mat dimg;
adaptiveThreshold(img,dimg,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,17,1);
dilate(dimg,img,GetKernel(2));
erode(img,dimg,GetKernel(2));
erode(dimg,img,GetKernel(1));
dimg = img;
//*
vector<vector<Point>> contours; // Vector for storing contour
vector<Vec4i> hierarchy;
findContours( dimg, contours, hierarchy,CV_RETR_TREE , CV_CHAIN_APPROX_NONE ); // Find the contours in the image
double largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
for( int i = 0; i< contours.size(); i ) // iterate through each contour.
{
double a=contourArea( contours[i],false); // Find the area of contour
if(a>largest_area){
largest_area=a;
largest_contour_index=i; //Store the index of largest contour
bounding_rect=boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
}
}
drawContours( imgC, contours, largest_contour_index, Scalar(255,0,0), 2, 8, hierarchy, 0, Point() );
rectangle(imgC, bounding_rect, Scalar(0,255,0),2, 8,0);
/**/
//imshow("display",dimg);
imshow("display2",imgC);
waitKey(0);
return 0;
}
Полученный результат:
При необходимости вы можете точно настроить пороговое значение.
Комментарии:
1. спасибо .. можете ли вы, пожалуйста, сказать мне, почему вы использовали «erode, затем dailate, затем erode»??
2. как вы думаете, если бы я использовал детектор Canny edge, я бы не получил тех же результатов??
3. Я не пробовал, но я думаю, что вы можете получить аналогичный результат, если будете использовать
dilate/erode
тем же способом, который использовал я.