opencv
Verwenden von Cascade Classifiers in Java
Suche…
Syntax
- CascadeClassifier cascade = neuer CascadeClassifier ("cascade.xml"); // Erstellt einen Kaskadenklassifizierer aus cascade.xml
- Mat image = Imgcodecs.imread ("image.png"); // Konvertiert image.png in ein Mat (Matrix) -Objekt
- MatOfRect-Erkennungen = new MatOfRect (); // Erstellt eine leere MatOfRect-Datei (Matrix of Rectangles), die als Ausgabe für unsere Erkennungsklassen verwendet wird
- detections.toArray (); // Gibt ein Array von Rect-Objekten zurück, das wiederholt werden kann
- Imgproc.rectangle (Bild, neuer Punkt (rect.x, rect.y), neuer Punkt (rect.x + rect.width, rect.y + rect.height), neuer Skalar (0, 255, 0)); // Zeichnet ein grün umrahmtes Rechteck von den x- und y-Positionen des ersten Punkts bis zum x- und y-Ort des zweiten Punkts auf das Mat-Objekt "image". "rect" ist ein Rect-Objekt, das normalerweise von detections.toArray () bereitgestellt wird. Verwendet die Point-Klasse von OpenCV.
- Imgcodecs.imwrite ("output.png", Bild); // schreibt das modifizierte Mat-Objekt "image" in die "output.png"
- CascadeClassifier.detectMultiScale (Bild, Erkennungen); // Erkennt ein beliebiges Objekt im Mat-Objekt "image" und gibt die Erkennungen im MatOfRect-Objekt "Erkennungen" aus
- CascadeClassifier.detectMultiScale (Bild, Erkennungen, scaleFactor , minNeighbors , Flags , minSize , maxSize ); // Führt eine Erkennung mit zusätzlichen Parametern durch. Details siehe unten.
- Imgproc.ellipse (Bild, Mittelpunkt, Achsen , 0, 0, 360, neuer Skalar (255, 0, 255), Dicke , Linientyp , 0); Zeichnet // eine Ellipse auf das Bild , an dem Punkt ,
center
. Verwendet die Point-Klasse von OpenCV.
Parameter
Parameter | Einzelheiten |
---|---|
Skalierungsfaktor | Um wie viel die Bildgröße bei jedem Bildmaßstab reduziert wird. Voreinstellung = 1.1 |
MinNeighbors | Wie viele Nachbarn sollte ein Kandidatenrechteck haben, bevor Sie es als erkanntes Objekt auswählen. Voreinstellung = 4 |
Flaggen | Alte Flaggen In den meisten Fällen sollte dies auf 0 . Voreinstellung = 0 |
minSize | Mindestgröße eines Kandidatenrechtecks. Hierbei wird die Size OpenCV verwendet. Kann verwendet werden, um die Erkennungszeit und die CPU-Auslastung zu verringern sowie Fehlalarme zu reduzieren. |
maximale Größe | Maximale Größe eines Kandidatenrechtecks. Hierbei wird die Size OpenCV verwendet. Kann verwendet werden, um die Erkennungszeit und die CPU-Auslastung zu verringern sowie Fehlalarme zu reduzieren. |
Achsen | Verwendet die Größenklasse von OpenCV. Definiert die Breite und Höhe der Ellipse. |
Dicke | Strichstärke in Pixeln. |
lineType | Hat verschiedene Parameter. 0 ist die durchgezogene Linie, 8 ist für eine Leitung mit 8 Verbindungen, 4 für eine Leitung mit 4 Verbindungen und CV_AA für eine CV_AA Leitung. Voreinstellung = 8 |
Ein statisches Bild erhalten, Elemente darin erkennen und die Ergebnisse ausgeben.
Bitte beachten Sie, dass dieses Beispiel OpenCV 3.1 verwendet.
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
public class Classifier {
private CascadeClassifier diceCascade = new
CascadeClassifier("res/newMethod/diceCascade.xml");
private Mat image;
private String loc = "path/to/image.png";
private String output = "path/to/output.png";
public void detImg() {
Mat image = Imgcodecs.imread(loc); // Reads the image
MatOfRect diceDetections = new MatOfRect(); // Output container
diceCascade.detectMultiScale(image, diceDetections); // Performs the detection
// Draw a bounding box around each detection.
for (Rect rect : diceDetections.toArray()) {
Imgproc.rectangle(image, new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0));
}
// Save the visualized detection.
Imgcodecs.imwrite(output, image);
}
}
Das von diceDetections.toArray()
zurückgegebene diceDetections.toArray()
Rect[]
kann wiederholt werden. Jedes Rect
im Array hat vier Haupteigenschaften: x
, y
, width
und height
. x
und y
definieren die linke obere Position des Rechtecks. width
und height
ein int
der Breite und Höhe des Rechtecks zurück. Dies wird verwendet, wenn Rechtecke auf Bilder gezeichnet werden. Die minimal erforderlichen Parameter der Funktion Imgproc.rectangle
lauten wie folgt:
Imgproc.rectangle(Mat image, Point start, Point end, Scalar color);
Beide Point
werden für die Positionen der oberen linken Ecke und der rechten unteren Ecke verwendet. Diese Positionen sind für das als ersten Parameter bereitgestellte Bild absolut und nicht für einander. Daher müssen Sie sowohl die x
als auch die y
Position des Rechtecks zusätzlich zur width
oder height
hinzufügen, um den end
richtig zu definieren.
Beachten Sie, dass die in diesen Parametern verwendete Point
Klasse nicht die Point
Klasse der Standardbibliothek von Java ist. Sie müssen stattdessen die Point
Klasse von OpenCV importieren!
Bilder von einem Videogerät erkennen
In diesem Beispiel wird die VideoCapture
Klasse vorgestellt, in der wir ein Bild von einer Webcam aufnehmen und in einem Bild speichern.
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
public class Classifier {
private CascadeClassifier diceCascade = new
CascadeClassifier("res/newMethod/diceCascade.xml");
private Mat image;
private String loc = "path/to/image.png";
private String output = "path/to/output.png";
private VideoCapture vc = new VideoCapture();
public void detImg() {
vc.open(0); // Opens the video stream
Mat image = new Mat(); // Creates an empty matrix
vc.read(image); // Reads the image from the video stream and
writes it to the image matrix.
MatOfRect diceDetections = new MatOfRect(); // Output container
diceCascade.detectMultiScale(image, diceDetections); // Performs the detection
// Draw a bounding box around each detection.
for (Rect rect : diceDetections.toArray()) {
Imgproc.rectangle(image, new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0));
}
// Save the visualized detection.
Imgcodecs.imwrite(output, image);
vc.release(); // Closes the stream.
}
}
Konvertieren eines Mat-Objekts in ein BufferedImage-Objekt
Dieses Beispiel von Daniel Baggio stammt direkt aus dieser StackExchange-Antwort , wurde jedoch aus Gründen der Übersichtlichkeit erneut veröffentlicht.
Diese Klasse nimmt ein Mat-Objekt und gibt das BufferedImage-Objekt zurück, das von den Bibliotheken javax.swing
verwendet wird. Dies kann von einem Graphics
Objekt zum Zeichnen des Bildes verwendet werden.
private BufferedImage toBufferedImage(Mat m) {
if (!m.empty()) {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (m.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
int bufferSize = m.channels() * m.cols() * m.rows();
byte[] b = new byte[bufferSize];
m.get(0, 0, b); // get all the pixels
BufferedImage image = new BufferedImage(m.cols(), m.rows(), type);
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(b, 0, targetPixels, 0, b.length);
return image;
}
return null;
}
Erkennungen in Erkennungen
In diesem Beispiel werden Würfel und die schwarzen Punkte auf den Würfeln (den Pips) als Objekt verwendet. Da das Beispiel ziemlich lang ist, ist es zunächst wichtig, einige Schlüsselbegriffe zu erklären, um das Beispiel zu verstehen.
Grundlegendes zum ersten Beispiel: "Ein statisches Bild abrufen, Elemente darin erkennen und die Ergebnisse ausgeben." Für das Verständnis dieses Beispiels ist es besonders wichtig, wie OpenCV Rechtecke zeichnet.
Schauen Sie sich das folgende Bild an:
Wir werden die Subimaging-Methode verwenden, bei der wir einen erkannten Bereich als Basis für weitere Erkennungen verwenden. Dies ist nur möglich, wenn sich ein Objekt immer in einem anderen Objekt befindet, das wir erkennen können, z. B. mit unseren Würfeln. Diese Methode hat mehrere Vorteile:
- Anstatt das gesamte Bild zu scannen, müssen wir nur den Bereich scannen, in dem sich das Objekt befindet.
- Entfernt die Möglichkeit von Fehlalarmen außerhalb des Erkennungsbereichs.
Wir machen dies, indem wir zuerst einen Kaskadenklassifizierer-Scan über das gesamte Bild anwenden, um ein MatOfRect
Objekt zu erhalten, das unsere großen Objekte (in diesem Fall Dice) enthält. Wir iterieren dann über das Rect[]
Array, das von der toArray()
Funktion aus dem MatOfRect
Objekt MatOfRect
wird. Dieses Rect
Objekt wird beim Erstellen eines temporären Mat
Objekts verwendet, das vom Originalbild auf die Eigenschaften des Rect
Objekts ( x, y, width, height
) "abgeschnitten" wird. Dort können wir dann das temporäre Mat
Objekt erkennen. Mit anderen Worten, wir weisen den Klassifizierer an, stattdessen nur Erfassungen an den Würfelteilen des Bildes durchzuführen, und wir geben die Position jedes Würfels an, indem wir die Rect
Objekte verwenden, die wir bei der Durchführung einer Erkennung für das gesamte Bild erhalten haben.
Die Rect
Objekte (Pips) haben jedoch ihre Eigenschaften im Verhältnis zu ihren Würfeln und nicht zum Bild selbst. Um dieses Problem zu lösen, wenn wir zum eigentlichen Bild zeichnen Rechtecken wollen die Kerne der Standorte zeigen, fügen wir beide dice.x
und dice.y
zum Point
.
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
public class Classifier {
private CascadeClassifier diceCascade =
new CascadeClassifier("res/newMethod/diceCascade.xml");
private CascadeClassifier pipCascade =
new CascadeClassifier("res/newMethod/pipCascade6.xml");
private VideoCapture vc = new VideoCapture();
private Mat image;
public void openVC(int index) {
vc.open(index);
}
public void closeVC() {
vc.close();
}
public Mat getNextImage() {
image = new Mat();
vc.read(image); // Sets the matrix to the current livestream frame.
MatOfRect diceDetections = new MatOfRect(); // Output container
// See syntax for explainations on addition parameters
diceCascade.detectMultiScale(image, diceDetections, 1.1, 4, 0, new Size(20, 20),
new Size(38, 38));
// Iterates for every Dice ROI
for (int i = 0; i < diceDetections.toArray().length; i++) {
Rect diceRect = diceDetections.toArray()[i];
// Draws rectangles around our detected ROI
Point startingPoint = new Point(diceRect.x, diceRect.y);
Point endingPoint = new Point(diceRect.x + diceRect.width,
diceRect.y + diceRect.height);
Imgproc.rectangle(image, startingPoint, endingPoint, new Scalar(255, 255, 0));
MatOfRect pipDetections = new MatOfRect();
pipCascade.detectMultiScale(image.submat(diceRect), pipDetections, 1.01, 4, 0,
new Size(2, 2), new Size(10, 10));
// Gets the number of detected pips and draws a cricle around the ROI
for (int y = 0; y < pipDetections.toArray().length; y++) {
// Provides the relative position of the pips to the dice ROI
Rect pipRect = pipDetections.toArray()[y];
// See syntax explaination
// Draws a circle around our pips
Point center = new Point(diceRect.x + pipRect.x + pipRect.width / 2,
diceRect.y + pipRect.y + pipRect.height / 2);
Imgproc.ellipse(image, center, new Size(pipRect.width / 2, pipRect.height / 2),
0, 0, 360, new Scalar(255, 0, 255), 1, 0, 0);
}
}
return image;
}
}
Die Funktion getNextImage()
gibt ein Mat
Objekt zurück, das zusammen mit den anderen veröffentlichten Beispielen ständig aufgerufen und in ein BufferImage
konvertiert werden BufferImage
, um einen Livestream anzuzeigen, der Erkennungen anzeigt.