使用 Opencv 跟踪彩球 Java

Tracking colored ball with Opencv Java

这是我第一次使用 opencv。我选择它是因为我有使用 JAVA 编码的经验。但是我在尝试解决我的编码问题时遇到了一些困难。

  1. 我的第一个问题:

我想从帧中捕捉颜色,这样当我用鼠标单击时它会给我 RGB 颜色,我可以将其转换为 HSV 并发送到我的 "inRange Method" 我可以跟踪我选择的任何颜色从我的框架。 它不起作用。它给我的颜色与我选择的颜色无关。

  1. 我的第二个问题:

我想检测物体的轮廓并检测它的位置或它与相机的距离,但我不确定如何。

这是我的代码:

package application;

import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.highgui.VideoCapture;
import org.opencv.imgproc.Imgproc;


public class FxController 
{
    double h=0,s=0,v=0,tolerance=10;
    @FXML 
    private Button start_b;
    @FXML 
    private ImageView currentFrame,currentFrame2;
    @FXML
    private Slider hSlider,sSlider,vSlider;
    @FXML
    private Label hLabel,sLabel,vLabel;

    private Pane rootElement;
    private Timer timer;
    private VideoCapture capture = new VideoCapture();
    private EventHandler handler;
    private  int red,green,bleu;
    private double alpha ;

    //private float hsb[];
     @FXML 
    protected void startCamera(ActionEvent event)
    {
        if(this.rootElement!=null)//savoir wache main class est accessible 
        {
            final ImageView frameView = currentFrame;//prendre l'objet ImageView pour montre le streaming
            final ImageView frameView2 = currentFrame2;
            /*handler = new EventHandler(){//clic dial la souris wesst l'image


                @Override
                public void handle(Event e) {
                    System.out.println("YOOOOO"+e.getEventType());


                }
            };*/
            frameView.setOnMouseClicked(Event->{Mat m= new Mat();
                                                    byte[] pixel=new byte[4];
                                                    //int [] rgb = new int[3];
                                                    float[] hsv = new float[3];
                                                    //Imgproc.cvtColor(grabMat(0),m,CvType.CV_8UC1);
                                                    grabMat(0).convertTo(m, CvType.CV_8UC3);
                                                    m.get((int)Event.getX(),(int)Event.getY(),pixel);
                                                    /*alpha=(pixel[0] >> 24) & 0xff;
                                                    red=(pixel[1] >> 16) & 0xff;
                                                    green=(pixel[2] >> 8) & 0xff;
                                                    bleu=(pixel[3]) & 0xff;*/
                                                    alpha=pixel[0] & 0xff;
                                                    red=pixel[1] & 0xff;
                                                    green=pixel[2] & 0xff;//fuuuuuuuuuuuuuuuuuuuuuck 
                                                    bleu=pixel[3] & 0xff;
                                                    hsv=java.awt.Color.RGBtoHSB(red,green,bleu, null);
                                                    System.out.println("alpha= "+alpha+"---red= "+red+"---bleu= "+bleu+"---green= "+green);
                                                    h= hsv[0];
                                                    s=hsv[1];
                                                    v=hsv[2];
                                                    System.out.println("h= "+h+"---s= "+s+"---v= "+v);
                                                    //Event.getX();//x du pixel ou la souris berkat
                                                    //Event.getY();
                                                    //BufferedImage.setRGB(Event.getX(),Event.getY(), Color.getRGB());
                                                    });

            if(!this.capture.isOpened())//voir est c que la capture stream est ouverte
            {
                this.capture.open(0);//commence la capture video 
                //prendre le fram chaque 33 ms(30 frames/sec)
                TimerTask FrameGrabber = new TimerTask(){
                    @Override 
                    public void run()
                    {
                        Image tmp = grabFrame(Imgproc.COLOR_RGB2RGBA);//imageRGB
                        //Image tmp2 = grabFrame(Imgproc.COLOR_RGB2HSV);
                        Image tmp3 = newColorDetection(grabMat(Imgproc.COLOR_BGR2HSV));
                        Platform.runLater(new Runnable(){
                            @Override 
                            public void run()
                            {
                                frameView.setImage(tmp);

                                frameView2.setImage(tmp3);
                            }
                        });
                    }
                };
                this.timer = new Timer();
                this.timer.schedule(FrameGrabber,0,33);
                this.start_b.setText("Stop Camera");
                }
            else 
            {
                this.start_b.setText("Start Camera");
                //arrete le timer
                if(this.timer!=null)
                {
                    this.timer.cancel();
                    this.timer = null;
                }
                //realease camera
                this.capture.release();
                //efface le contenaire d'image 
                frameView.setImage(null);
                frameView2.setImage(null);
            }

        }
    }



    private Image grabFrame(int img)
    {
        Image imageToShow =null;//init
        Mat frame = new Mat();// cree une matrice
        //checker si la capture est ouverte
        if(this.capture.isOpened())
        {
            try{
                this.capture.read(frame);//lire le frame courant
                //test si le frame est vide
                if(!frame.empty())
                {
                    //convertire l'image au gris
                    Imgproc.cvtColor(frame, frame,img);
                    //convertir la Mat (objet) a Image (javaFx)
                    imageToShow = mat2Image(frame);
                }
            }catch(Exception e){System.err.println("ERROR: "+e.getMessage());}
        }
        return imageToShow;

    }
    private Mat grabMat(int img)
    {
        Image imageToShow =null;//init
        Mat frame = new Mat();// cree une matrice
        //checker si la capture est ouverte
        if(this.capture.isOpened())
        {
            try{
                this.capture.read(frame);//lire le frame courant
                //test si le frame est vide
                if(!frame.empty())
                {
                    //convertire l'image au gris
                    Imgproc.cvtColor(frame, frame,img);
                    //convertir la Mat (objet) a Image (javaFx)

                }
            }catch(Exception e){System.err.println("ERROR: "+e.getMessage());}
        }

        return frame;

    }


    private Image matToThresHolded(Mat frame)
    {   Image thresHoldedImg =null;
        Mat dFrame = new Mat();
        Imgproc.threshold(frame, dFrame, 127, 255,Imgproc.THRESH_TOZERO);
        thresHoldedImg=mat2Image(dFrame);
        return thresHoldedImg;
    }
    private Image mat2Image (Mat frame)
    {   //cree un buffer temporaire
        MatOfByte buffer = new MatOfByte();
        //encode le frame dans le buffer
        Highgui.imencode(".png",frame, buffer);
        //construire et retourne une image cree depuis l'image encode dans le buffer
        return new Image(new ByteArrayInputStream(buffer.toArray()));

    }
    public void setRootElement(Pane root)
    {
        this.rootElement = root;
    }
    public Image colorDetection(Mat hsvImage)
    {
        Image imageToShow=null;
        Mat threshedImg =new Mat();
        //Scalar hsvMin=new Scalar(106,60,90,0);//red
        //Scalar hsvMax=new Scalar(124,255,255,0);//red
        Scalar hsvMin=new Scalar(100,150,100);//bleu
        Scalar hsvMax=new Scalar(140,255,255);//bleu
    Core.inRange(hsvImage,hsvMin, hsvMax, threshedImg);
    imageToShow = mat2Image(threshedImg);
     return imageToShow;
    }
    public  Image newColorDetection(Mat hsv)
    {

        Image imageToShow=null;
        Mat threshedImg =new Mat(); 
        Mat threshedImg2 =new Mat();    
        Scalar hsvMin = new Scalar(0, 50, 50, 0);//red
        Scalar hsvMax = new Scalar(6, 255, 255, 0);//red
        Scalar hsvMin2 = new Scalar(175, 50, 50, 0);//red
        Scalar hsvMax2 = new Scalar(179, 255, 255, 0);//red
        //Scalar hsvMin=new Scalar(100,150,100);//bleu
        //Scalar hsvMax=new Scalar(140,255,255);//bleu
        //Scalar hsvMin=new Scalar(h-tolerance-1, s-tolerance, 0);//default
        //Scalar hsvMax=new Scalar(h+tolerance-1, s+tolerance,255);//default
     Core.inRange(hsv,hsvMin,hsvMax,threshedImg);
     Core.inRange(hsv, hsvMin2, hsvMax2, threshedImg2);
     Core.bitwise_or(threshedImg, threshedImg2, threshedImg);
    // dilate et erosion pour renforce l'image et supprime les pixels lmcheyrin 
    Mat dilate = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE, new Size(3, 3));
        Imgproc.dilate(threshedImg, threshedImg, dilate);//dilate   
    Mat erode = Imgproc.getStructuringElement(Imgproc.MORPH_ERODE, new Size(3, 3));
        Imgproc.erode(threshedImg, threshedImg, erode);
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();    
        Imgproc.findContours(threshedImg, contours, new Mat(), Imgproc.RETR_LIST,Imgproc.CHAIN_APPROX_SIMPLE);
        imageToShow = mat2Image(threshedImg);
     return imageToShow;

    }
}

我的主要

package application;

import org.opencv.core.Core;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("FristProjectFX.fxml"));
            BorderPane root = (BorderPane)loader.load();
            Scene scene = new Scene(root);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setTitle("JavaFx YO!");
            primaryStage.setAlwaysOnTop(true);
            primaryStage.setScene(scene);
            primaryStage.show();//show GUI
            FxController controller = loader.getController();
            controller.setRootElement(root);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        launch(args);
    }
}

这是我得到的

就像你在下图中看到的那样,当我点击红色区域时,我没有得到红色代码,甚至对于其他颜色也是如此。

我的期望是

就像你在图片上看到的那样我可以接住球和距离!

我找到了第一个问题的答案

frameView.setOnMouseClicked(Event->{
    Mat m= new Mat();
    double[] pixel=new double[3];
    float[] hsv = new float[3];
    grabMat(0).convertTo(m, CvType.CV_8U);
    Imgproc.cvtColor(m, m, Imgproc.COLOR_BGR2RGB, 3);
    pixel=m.get((int)Event.getX(),(int)Event.getY());
    red=pixel[0];
    green=pixel[1];
    bleu=pixel[2];
    System.out.println("X= "+Event.getX()+"Y="+Event.getY()+"---red= "+red+"---bleu= "+bleu+"---green= "+green);
    hsv=java.awt.Color.RGBtoHSB((int)red,(int)green,(int)bleu, null);
    h= hsv[0];
    s=hsv[1];
    v=hsv[2];
    System.out.println("h= "+h+"---s= "+s+"---v= "+v);                              
});