opencv
Använda Cascade Classifiers i Java
Sök…
Syntax
- CascadeClassifier cascade = new CascadeClassifier ("cascade.xml"); // Skapar en kaskadklassificering från cascade.xml
- Mattbild = Imgcodecs.imread ("image.png"); // Konverterar image.png till ett Mat (Matrix) -objekt
- MatOfRect-detektioner = ny MatOfRect (); // Skapar en tom MatOfRect-fil (Matrix of Rectangles) som används som utgång för våra upptäcktsklasser
- detections.toArray (); // Returnerar en matris med Rect-objekt som kan itereras över
- Imgproc.rectangle (bild, ny punkt (rekt.x, rekt.y), ny punkt (rekt.x + rektvidd, rät.y + rekt.höjd), ny skalär (0, 255, 0)); // Ritar en grön rektangel från den första punktens x- och y-plats till den andra punktens x- och y-plats på Mat-objektets "bild". "rect" är ett Rect-objekt som vanligtvis tillhandahålls av detections.toArray (). Använder OpenCVs Point-klass.
- Imgcodecs.imwrite ("output.png", bild); // Skriver det modifierade Mat-objektet "image" till "output.png"
- CascadeClassifier.detectMultiScale (bild, detektioner); // Upptäcker alla objekt i Mat-objektets "bild" och matar upp detekteringarna i MatOfRect-objektet "detektioner"
- CascadeClassifier.detectMultiScale (bild, detektioner, skalaFactor , minNabbor , flaggor , minSize , maxSize ); // Utför en detektion med ytterligare parametrar. Se detaljerna nedan.
- Imgproc.ellipse (bild, centrum, axlar , 0, 0, 360, ny Scalar (255, 0, 255), tjocklek , linjetyp , 0); // Ritar en ellips på bilden i
center
. Använder OpenCVs Point-klass.
parametrar
Parameter | detaljer |
---|---|
skalfaktor | Hur mycket bildstorleken minskar vid varje bildskala. Standard = 1.1 |
minNeighbors | Hur många grannar en kandidatrektangel ska ha innan du väljer den som ett upptäckt objekt. Standard = 4 |
flaggor | Legacy flaggor. I de flesta fall bör detta ställas in på 0 . Standard = 0 |
minSize | Minsta storlek en kandidat rektangel kan vara. Detta använder OpenCV: s Size . Kan användas för att minska detekteringstiden och CPU-användningen samt för att minska falska positiver. |
maxSize | Maximal storlek en kandidat rektangel kan vara. Detta använder OpenCV: s Size . Kan användas för att minska detekteringstiden och CPU-användningen samt för att minska falska positiver. |
axlar | Använder OpenCV: s storleksklass. Definierar ellipsens bredd och höjd. |
tjocklek | Linjens tjocklek, i pixlar. |
linjetyp | Har olika parametrar. 0 är den heldragna linjen, 8 är för en 8-ansluten linje, 4 är för en 4-ansluten linje och CV_AA är för en antialiated linje. Standard = 8 |
Få en statisk bild, upptäcka objekt på den och mata ut resultaten.
Observera att det här exemplet använder OpenCV 3.1.
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);
}
}
Rect[]
returneras av diceDetections.toArray()
kan itereras över. Varje Rect
inne i matrisen har fyra huvudegenskaper: x
, y
, width
och height
. x
och y
definierar rektangelns position uppe till vänster, och width
och height
returnerar ett int
av rektangelns bredd och höjd. Detta används när du ritar rektanglar på bilder. Imgproc.rectangle
funktionens minimala nödvändiga parametrar är följande:
Imgproc.rectangle(Mat image, Point start, Point end, Scalar color);
Båda Point
används för positionerna i det övre vänstra hörnet och det nedre högra hörnet. Dessa positioner är båda absoluta för den bild som tillhandahålls som den första parametern, inte för varandra. Därför måste du lägga till både rektangelns x
eller y
position förutom width
eller height
att korrekt definiera end
.
Observera att Point
klassen som används i dessa parametrar är inte Java standard bibliotekets Point
klass. Du måste importera OpenCVs Point
klass istället!
Upptäcker bilder från en videoenhet
Detta exempel introducerar klassen VideoCapture
, där vi använder den för att ta en bild från en webbkamera och spara den i en bild.
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.
}
}
Konvertera ett Mat-objekt till ett BufferedImage-objekt
Exemplet av Daniel Baggio togs direkt från detta StackExchange-svar , men har omposterats för synlighet.
Den här klassen tar ett Mat-objekt och returnerar BufferedImage-objektet som används av javax.swing
biblioteken. Detta kan användas av ett Graphics
att rita bilden.
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;
}
Upptäckter inom upptäckter
Det här exemplet använder Tärningar och de svarta fläckarna på tärningarna (pips) som vårt objekt. Eftersom exemplet är ganska långt, är det avgörande för att förstå exemplet att först förklara några viktiga begrepp.
Förstå det första exemplet "Få en statisk bild, upptäcka objekt på den och mata ut resultaten." är avgörande för att förstå detta exempel, särskilt hur OpenCV drar rektanglar.
Titta på följande bild:
Vi kommer att använda subimaging-metoden, där vi använder ett detekterat område som bas för att tillämpa fler upptäckter. Detta är bara möjligt om ett objekt alltid kommer att finnas inom ett annat objekt som vi kan upptäcka, till exempel våra pips på våra tärningar. Denna metod har flera fördelar:
- Istället för att skanna hela bilden behöver vi bara skanna det område där vi vet att objektet kommer att befinna sig.
- Tar bort alla risker för falska positiver utanför detekteringsområdet.
Vi gör detta genom att först tillämpa en kaskadklassificeringssökning över hela bilden för att ge oss ett MatOfRect
objekt som innehåller våra stora objekt (tärningar, i det här fallet). Vi itererar sedan över Rect[]
-fältet som ges av toArray()
från MatOfRect
objektet. Detta Rect
objekt används för att skapa ett tillfälligt Mat
objekt som "beskärs" till Rect
objektets egenskaper ( x, y, width, height
) från den ursprungliga bilden, där vi sedan kan utföra detekteringar på det temporära Mat
objektet. Med andra ord säger vi klassificeringen att bara utföra detekteringar på tärningsdelarna i bilden istället, och vi anger platsen för varje tärning genom att använda Rect
objekten som vi fick från att utföra en detektering på hela bilden.
Rect
objekten (pips) har emellertid sina egenskaper relativt deras tärningar och inte själva bilden. För att lösa det här problemet, när vi vill dra rektanglar till den verkliga bilden visar pips positioner, lägger vi både dice.x
och dice.y
till 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;
}
}
getNextImage()
returnerar ett Mat
objekt, som tillsammans med de andra exemplen som publiceras kan kallas ständigt och kan konverteras till en BufferImage
att ge en livestream som visar detekteringar.