opencv
Utilisation de classificateurs en cascade en Java
Recherche…
Syntaxe
- CascadeClassifier cascade = new CascadeClassifier ("cascade.xml"); // Crée un classificateur en cascade à partir de cascade.xml
- Mat image = Imgcodecs.imread ("image.png"); // Convertit image.png en un objet Mat (Matrix)
- Détections MatOfRect = new MatOfRect (); // Crée un fichier MatOfRect (Matrix of Rectangles) vide, utilisé comme sortie pour nos classes de détection
- detections.toArray (); // Retourne un tableau d'objets Rect pouvant être itéré sur
- Imgproc.rectangle (image, nouveau point (rect.x, rect.y), nouveau point (rect.x + rect.width, rect.y + rect.height), nouveau scalaire (0, 255, 0)); // Dessine un rectangle à contour vert depuis les emplacements x et y du premier point vers l'emplacement x et y du second point sur l'objet Mat "image". "rect" est un objet Rect, généralement fourni par detections.toArray (). Utilise la classe de points OpenCV.
- Imgcodecs.imwrite ("output.png", image); // Ecrit l'objet Mat modifié "image" dans le fichier "output.png"
- CascadeClassifier.detectMultiScale (image, détections); // Détecte tout objet dans l'objet Mat "image" et affiche les détections dans l'objet MatOfRect "détections"
- CascadeClassifier.detectMultiScale (image, détections, scaleFactor , minNeighbors , flags , minSize , maxSize ); // Effectue une détection avec des paramètres supplémentaires. Voir les détails ci-dessous.
- Imgproc.ellipse (image, centre, axes , 0, 0, 360, nouveau Scalar (255, 0, 255), épaisseur , lineType , 0); // Dessine une ellipse sur l'image au
center
du point. Utilise la classe de points OpenCV.
Paramètres
Paramètre | Détails |
---|---|
facteur d'échelle | Combien la taille de l'image est réduite à chaque échelle d'image. Par défaut = 1.1 |
minNeighbors | Combien de voisins un rectangle candidat doit avoir avant de le sélectionner comme objet détecté. Par défaut = 4 |
drapeaux | Drapeaux hérités Dans la plupart des cas, cela devrait être mis à 0 . Par défaut = 0 |
minSize | La taille minimale d'un rectangle candidat peut être. Cela utilise la classe de Size OpenCV. Peut être utilisé pour réduire le temps de détection et l'utilisation du processeur, ainsi que pour réduire les faux positifs. |
taille max | Taille maximale que peut contenir un rectangle candidat. Cela utilise la classe de Size OpenCV. Peut être utilisé pour réduire le temps de détection et l'utilisation du processeur, ainsi que pour réduire les faux positifs. |
les axes | Utilise la classe de taille OpenCV. Définit la largeur et la hauteur de l'ellipse. |
épaisseur | Épaisseur de la ligne, en pixels. |
type de ligne | A divers paramètres. 0 correspond à la ligne CV_AA , 8 ligne à 8 connexions, 4 ligne à 4 connexions et CV_AA à la ligne antialiasée. Par défaut = 8 |
Obtenir une image statique, détecter les éléments et afficher les résultats.
Veuillez noter que cet exemple utilise 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);
}
}
Le Rect[]
renvoyé par diceDetections.toArray()
peut être itéré sur. Chaque Rect
à l'intérieur du tableau aura quatre propriétés principales: x
, y
, width
et height
. x
et y
définissent la position supérieure gauche du rectangle et width
et height
renvoie un int
de la largeur et de la hauteur du rectangle. Ceci est utilisé pour dessiner des rectangles sur des images. Les paramètres requis minimaux de la fonction Imgproc.rectangle
sont les suivants:
Imgproc.rectangle(Mat image, Point start, Point end, Scalar color);
Les deux Point
sont utilisés pour les positions du coin supérieur gauche et du coin inférieur droit. Ces positions sont à la fois absolues sur l'image fournie comme premier paramètre et non sur l'autre. Vous devez donc ajouter la position x
ou y
du rectangle en plus de la width
ou de la height
pour définir correctement le point de end
.
Notez que la classe Point
utilisée dans ces paramètres n'est pas la classe Point
la bibliothèque standard de Java. Vous devez importer la classe de Point
OpenCV à la place!
Détection d'images à partir d'un périphérique vidéo
Cet exemple présente la classe VideoCapture
, où nous l'utilisons pour prendre une image à partir d'une webcam et l'enregistrer sur une image.
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.
}
}
Conversion d'un objet Mat en objet BufferedImage
Cet exemple de Daniel Baggio a été tiré directement de cette réponse StackExchange , mais a été republié pour la visibilité.
Cette classe prend un objet Mat et renvoie l'objet BufferedImage utilisé par les bibliothèques javax.swing
. Cela peut être utilisé par un objet Graphics
pour dessiner l'image.
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;
}
Détections dans les détections
Cet exemple utilise Dice et les points noirs sur les dés (les pips) comme objet. Comme l'exemple est assez long, expliquer d'abord certains concepts clés est essentiel pour comprendre l'exemple.
Comprendre le premier exemple, "Obtention d’une image statique, détection des éléments et sortie des résultats". est essentiel pour comprendre cet exemple, en particulier comment OpenCV dessine des rectangles.
Regardez l'image suivante:
Nous utiliserons la méthode de sous-application, où nous utiliserons une zone détectée comme base pour appliquer davantage de détections. Ceci n'est possible que si un objet se trouve toujours dans un autre objet que nous pouvons détecter, comme nos pips sur nos dés. Cette méthode présente plusieurs avantages:
- Au lieu de scanner l'image entière, il suffit de scanner la zone dans laquelle nous savons que l'objet se trouvera.
- Supprime toute possibilité de faux positifs en dehors de la zone de détection.
Nous faisons cela en appliquant d'abord un balayage classificateur en cascade sur l'image entière pour nous donner un objet MatOfRect
contenant nos grands objets (dés, dans ce cas). Nous parcourons ensuite le tableau Rect[]
donné par la fonction toArray()
de l'objet MatOfRect
. Cet objet Rect
est utilisé pour créer un objet Mat
temporaire qui est "recadré" aux propriétés de l'objet Rect
( x, y, width, height
) à partir de l'image d'origine, où nous pouvons alors effectuer des détections sur l'objet Mat
temporaire. En d'autres termes, nous demandons au classificateur de ne faire que des détections sur les parties de dés de l'image, et nous spécifions la position de chaque dé en utilisant les objets Rect
obtenus en effectuant une détection sur l'image entière.
Cependant, les objets Rect
(pips) ont leurs propriétés par rapport à leurs dés, et non à l'image elle-même. Pour résoudre ce problème, lorsque nous voulons dessiner des rectangles à l'image réelle montrant l'emplacement des pépins, nous ajoutons à la fois dice.x
et dice.y
au Point
départ.
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;
}
}
La fonction getNextImage()
renvoie un objet Mat
, qui, associé aux autres exemples publiés, peut être appelé en permanence et peut être converti en BufferImage
pour fournir un flux de diffusion affichant les détections.