opencv
Cascade Classifiers gebruiken in Java
Zoeken…
Syntaxis
- CascadeClassifier cascade = nieuwe CascadeClassifier ("cascade.xml"); // Maakt een cascade-classifier van cascade.xml
- Mat afbeelding = Imgcodecs.imread ("image.png"); // Converteert image.png naar een Mat (Matrix) -object
- MatOfRect detecties = nieuwe MatOfRect (); // Maakt een leeg MatOfRect-bestand (Matrix of Rectangles) dat wordt gebruikt als uitvoer voor onze detectieklassen
- detections.toArray (); // Retourneert een reeks Rect-objecten die kunnen worden herhaald
- Imgproc.rectangle (afbeelding, nieuw punt (rect.x, rect.y), nieuw punt (rect.x + rect.width, rect.y + rect.height), nieuwe Scalar (0, 255, 0)); // Tekent een groen omlijnde rechthoek van de x- en y-locaties van het eerste punt naar de x- en y-locatie van het tweede punt op de "afbeelding" van het Mat-object. "rect" is een object Rect, meestal geleverd door detections.toArray (). Gebruikt de Point-klasse van OpenCV.
- Imgcodecs.imwrite ("output.png", afbeelding); // Schrijft het gewijzigde Mat-object "image" naar de "output.png"
- CascadeClassifier.detectMultiScale (afbeelding, detecties); // Detecteert elk object in het Mat-object "afbeelding" en voert de detecties uit in het MatOfRect-object "detecties"
- CascadeClassifier.detectMultiScale (afbeelding, detecties, scaleFactor , minNeighbours , vlaggen , minSize , maxSize ); // Voert een detectie uit met aanvullende parameters. Zie de onderstaande details.
- Imgproc.ellipse (afbeelding, midden, assen , 0, 0, 360, nieuwe Scalar (255, 0, 255), dikte , lineType , 0); // Tekent een ellips op de afbeelding in het
center
van het punt. Gebruikt de Point-klasse van OpenCV.
parameters
Parameter | Details |
---|---|
schaal factor | Hoeveel de afbeeldingsgrootte op elke afbeeldingsschaal wordt verkleind. Standaard = 1.1 |
minNeighbors | Hoeveel buren een kandidaat-rechthoek moet hebben voordat deze als een gedetecteerd object wordt geselecteerd. Standaard = 4 |
vlaggen | Oude vlaggen. In de meeste gevallen moet dit op 0 worden ingesteld. Standaard = 0 |
minSize | Minimale grootte die een kandidaat-rechthoek kan zijn. Dit maakt gebruik van de klasse Size OpenCV. Kan worden gebruikt om de detectietijd en het CPU-gebruik te verminderen en om valse positieven te verminderen. |
maxSize | Maximale grootte die een kandidaat-rechthoek kan zijn. Dit maakt gebruik van de klasse Size OpenCV. Kan worden gebruikt om de detectietijd en het CPU-gebruik te verminderen en om valse positieven te verminderen. |
as | Gebruikt OpenCV's Size-klasse. Bepaalt de breedte en hoogte van de ellips. |
dikte | Dikte van de lijn, in pixels. |
Linetype | Heeft verschillende parameters. 0 is de ononderbroken lijn, 8 is voor een 8-verbonden lijn, 4 is voor een 4-verbonden lijn en CV_AA is voor een CV_AA . Standaard = 8 |
Een statisch beeld krijgen, items erop detecteren en de resultaten uitvoeren.
Merk op dat dit voorbeeld OpenCV 3.1 gebruikt.
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);
}
}
De Rect[]
geretourneerd door diceDetections.toArray()
kan worden herhaald. Elk Rect
in de array heeft vier hoofdeigenschappen: x
, y
, width
en height
. x
en y
definiëren de positie linksboven van de rechthoek en width
en height
retourneert een int
van de breedte en hoogte van de rechthoek. Dit wordt gebruikt bij het tekenen van rechthoeken op afbeeldingen. De minimaal vereiste parameters van de functie Imgproc.rectangle
zijn als volgt:
Imgproc.rectangle(Mat image, Point start, Point end, Scalar color);
Beide Point
worden gebruikt voor de functies van de linkerbovenhoek en de rechteronderhoek. Deze posities zijn beide absoluut voor de afbeelding die als eerste parameter wordt gegeven, niet voor elkaar. U moet dus zowel de x
of y
positie van de rechthoek toevoegen naast de width
of height
om het end
correct te definiëren.
Merk op dat de Point
klasse die in deze parameters wordt gebruikt, niet de Point
klasse van Java's standaardbibliotheek is. In plaats daarvan moet u de Point
klasse van OpenCV importeren!
Afbeeldingen van een videoapparaat detecteren
Dit voorbeeld introduceert de VideoCapture
klasse, waar we deze gebruiken om een afbeelding van een webcam te maken en op te slaan in een afbeelding.
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.
}
}
Een Mat-object omzetten in een BufferedImage-object
Dit voorbeeld van Daniel Baggio is rechtstreeks overgenomen uit dit StackExchange-antwoord , maar is opnieuw geplaatst voor zichtbaarheid.
Deze klasse neemt een Mat-object en retourneert het BufferedImage-object dat wordt gebruikt door de javax.swing
bibliotheken. Dit kan door een Graphics
object worden gebruikt om de afbeelding te tekenen.
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;
}
Detecties binnen detecties
Dit voorbeeld gebruikt dobbelstenen en de zwarte vlekken op de dobbelstenen (de pips) als ons object. Omdat het voorbeeld vrij lang is, is het eerst van cruciaal belang om enkele sleutelconcepten uit te leggen om het voorbeeld te begrijpen.
Inzicht in het eerste voorbeeld: "Een statische afbeelding ophalen, items erop detecteren en de resultaten uitvoeren." is van cruciaal belang om dit voorbeeld te begrijpen, vooral hoe OpenCV rechthoeken tekent.
Bekijk de volgende afbeelding:
We zullen de subimaging-methode gebruiken, waarbij we een gedetecteerd gebied gebruiken als basis voor het toepassen van meer detecties. Dit is alleen mogelijk als een object zich altijd in een ander object bevindt dat we kunnen detecteren, zoals onze pitten op onze dobbelstenen. Deze methode heeft verschillende voordelen:
- In plaats van de hele afbeelding te scannen, hoeven we alleen het gebied te scannen waar we weten dat het object zich zal bevinden.
- Verwijdert elke kans op valse positieven buiten het detectiegebied.
We doen dit door eerst een cascade-classificatiescan over de hele afbeelding toe te passen om ons een MatOfRect
object te geven dat onze grote objecten bevat (dobbelstenen, in dit geval). Vervolgens doorlopen we de Rect[]
toArray()
gegeven door de functie toArray()
van het object MatOfRect
. Dit object Rect
wordt gebruikt bij het maken van een tijdelijk Mat
object dat wordt "bijgesneden" naar de eigenschappen van het Rect
object ( x, y, width, height
) van de oorspronkelijke afbeelding, waar we vervolgens detecties kunnen uitvoeren op het tijdelijke Mat
object. Met andere woorden, we vertellen de classificator om in plaats daarvan alleen detecties uit te voeren op de dobbelsteengedeelten van de afbeelding, en we specificeren de positie van elke dobbelsteen met behulp van de Rect
objecten die we hebben gekregen van het uitvoeren van een detectie op de hele afbeelding.
De Rect
objecten (pips) hebben echter hun eigenschappen ten opzichte van hun dobbelstenen, en niet de afbeelding zelf. Om dit probleem op te lossen, als we willen rechthoeken vestigen op de werkelijke afbeelding die plaatsen de pitten, voegen we zowel dice.x
en dice.y
naar de start 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;
}
}
De functie getNextImage()
retourneert een Mat
object, dat samen met de andere geposte voorbeelden constant kan worden aangeroepen en kan worden geconverteerd naar een BufferImage
, om een livestream te bieden die detecties BufferImage
.