OpenCV - удалить неправильные контуры
У меня короткий вопрос об OpenCV и поиске конкретных форм. На моем компьютере у меня есть изображение с некоторыми формами, но я хочу только контуры прямоугольников:
Что я сделал:
- Откройте мое изображение и конвертируйте его в OpenCV Mat.
- Сделано некоторое изображение, обрабатывающее [оттенки серого, размытие]
- Найдены ребра с Canny
- Найдены контуры с помощью "findContours"
- Нарисуйте прямоугольники вокруг моих контуров с помощью "boundingRect"
И вот где я застрял. Я не знаю, как устранить неправильные контуры. Я попробовал это с перебрать мои контуры и удалить те, которые не правы. Но я понятия не имею, как найти неправильные контуры. Есть ли какие-либо формулы, которые я должен использовать или что-то еще. как это? Я нашел что-то с "arcLength", но я не понимаю этого.
Вот мой код:
package main;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import helper.ImageProcHelper;
public class Main {
public static void main(String[] args) throws Exception {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
File file = new File("C:\\Users\\Enrico Gründig\\Desktop\\Samples\\pic4.png");
Mat mat = new Mat(CvType.CV_8UC4);
Mat procMat = new Mat();
Mat hierarchy = new Mat();
Scalar color = new Scalar(0,0,255);
List<MatOfPoint> contours = new ArrayList<>();
try {
BufferedImage picture = ImageIO.read(file);
BufferedImage image = new BufferedImage(picture.getWidth(), picture.getHeight(), 5);
image.getGraphics().drawImage(picture, 0, 0, null);
System.out.println(image.getType());
mat = ImageProcHelper.ImageToMat(image);
Imgproc.cvtColor(mat, procMat, Imgproc.COLOR_RGBA2GRAY);
Imgproc.blur(procMat, procMat, new Size(3,3));
Imgproc.Canny(procMat, procMat, 127, 255);
//Konturen finden
Imgproc.findContours(procMat, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint2f[] contoursPoly = new MatOfPoint2f[contours.size()];
Rect[] boundRect = new Rect[contours.size()];
for(int i = 0; i < contours.size(); i++) {
contoursPoly[i] = new MatOfPoint2f();
Imgproc.approxPolyDP(new MatOfPoint2f(contours.get(i).toArray()), contoursPoly[i], 0.1, true);
boundRect[i] = Imgproc.boundingRect(new MatOfPoint(contours.get(i).toArray()));
}
for (int i = 0; i < contours.size(); i++) {
Imgproc.rectangle(mat, boundRect[i].tl(), boundRect[i].br(), color, 1);
}
image = ImageProcHelper.MatToImage(mat);
ImageIO.write((RenderedImage)image, "png", new File ("C:\\Users\\Enrico Gründig\\Desktop\\Samples\\output.png"));
} catch (IOException e) {
System.out.println("Error");
}
}
}
В чем смысл этого проекта:
Я получил IP-камеру потокового видео. И в этом проекте я хочу найти все QR-коды в потоке, обрезать их и передать их в декодер (например, ZXing). Я пробовал это только с ZXing, но у меня были проблемы с углом, размером и так далее. Вот почему я хочу использовать OpenCV, чтобы найти коды и манипулировать ими, чтобы уменьшить трафик с IP-камеры на декодер и (возможно) увеличить коэффициент попадания.
Большое спасибо за вашу помощь.
1 ответ
У меня недостаточно репутации, чтобы комментировать, но то, что вы, похоже, упускаете, - это проверка, чтобы получить стороны каждого контура. В вашем коде вам нужно использовать contoursPoly[i].size(), чтобы различать разные формы. Ваш код должен выглядеть примерно так:
package main;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import helper.ImageProcHelper;
public class Main {
public static void main(String[] args) throws Exception {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
File file = new File("C:\\Users\\Enrico Gründig\\Desktop\\Samples\\pic4.png");
Mat mat = new Mat(CvType.CV_8UC4);
Mat procMat = new Mat();
Mat hierarchy = new Mat();
Scalar color = new Scalar(0,0,255);
List<MatOfPoint> contours = new ArrayList<>();
try {
BufferedImage picture = ImageIO.read(file);
BufferedImage image = new BufferedImage(picture.getWidth(), picture.getHeight(), 5);
image.getGraphics().drawImage(picture, 0, 0, null);
System.out.println(image.getType());
mat = ImageProcHelper.ImageToMat(image);
Imgproc.cvtColor(mat, procMat, Imgproc.COLOR_RGBA2GRAY);
Imgproc.blur(procMat, procMat, new Size(3,3));
Imgproc.Canny(procMat, procMat, 127, 255);
//Konturen finden
Imgproc.findContours(procMat, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint2f[] contoursPoly = new MatOfPoint2f[contours.size()];
Rect[] boundRect = new Rect[contours.size()];
for(int i = 0; i < contours.size(); i++) {
contoursPoly[i] = new MatOfPoint2f();
Imgproc.approxPolyDP(new MatOfPoint2f(contours.get(i).toArray()), contoursPoly[i], 0.1, true);
boundRect[i] = Imgproc.boundingRect(new MatOfPoint(contours.get(i).toArray()));
}
for (int i = 0; i < contours.size(); i++) {
if (contoursPoly[i].size()>15){
Imgproc.rectangle(mat, boundRect[i].tl(), boundRect[i].br(), color, 1);
}
}
image = ImageProcHelper.MatToImage(mat);
ImageIO.write((RenderedImage)image, "png", new File ("C:\\Users\\Enrico Gründig\\Desktop\\Samples\\output.png"));
} catch (IOException e) {
System.out.println("Error");
}
}
}
У меня нет настройки Java с OpenCV, поэтому я не смог протестировать этот код, но идея пришла по этой ссылке. Возможно, вам придется возиться с "15", чтобы различать прямоугольник и круг.