2

Hello :) I'm using openCV library in java. I have a video of a mouse running on wheel. On the wheel, I have put a marker. I need to know how many loops does the mouse run on it. So to do this, I need to track the marker on the wheel.

I wrote the code, but I can't really get the specific range of colors to put in the Scalar class. Please help me with that, it's a school project!

This is the link to the video: https://www.dropbox.com/s/ssjyqmlm8kgj8uo/vid-light.avi?dl=0

I know that the video is looking bad, but that is what I have. :(

and this is the code:

public class VideoTracker {
    private Panel videoPanel;
    private Panel hsvPanel;
    private Panel thresholdPanel;
    private JFrame videoFrame;
    private JFrame hsvFrame;
    private JFrame thresholdFrame;
    private Mat frame;
    private Mat hsv;
    private Mat threshold;
    private Mat threshold2;
    private String path;
    private Pixel markerDetails;

    public VideoTracker(String videoPath) {
        videoPanel = new Panel();
        hsvPanel = new Panel();
        thresholdPanel = new Panel();
        videoFrame = new JFrame("Camera");
        hsvFrame = new JFrame("HSV");
        thresholdFrame = new JFrame("Threshold");
        frame = new Mat(640,480,3);
        hsv = new Mat();
        threshold = new Mat();
        threshold2 = new Mat();
        path = videoPath;
        markerDetails = new Pixel();
    }

public void trackWhite() throws AWTException {
            initializeJFrames();
            addClickEvent();
            //Read the video file
            VideoCapture capture = new VideoCapture(path);
            capture.set(3, 1366);
            capture.set(4, 768);
            capture.set(15, -2);
            capture.read(frame);
            videoFrame.setSize(frame.width() + 40, frame.height() + 60);
            hsvFrame.setSize(frame.width() + 40, frame.height() + 60);
            thresholdFrame.setSize(frame.width() + 40, frame.height() + 60);
            Mat array255 = new Mat(frame.height(), frame.width(), CvType.CV_8UC1);
            array255.setTo(new Scalar(255));
            Mat distance = new Mat(frame.height(), frame.width(), CvType.CV_8UC1);
            List<Mat> hsvList = new ArrayList<Mat>(3);
            Mat circles = new Mat(); // No need (and don't know how) to initialize it.
            // The function later will do it... (to a 1*N*CV_32FC3)
            Scalar hsv_min = new Scalar(markerDetails.getBlue()/2 - 20 < 0 ? 0 : markerDetails.getBlue()/2 - 20,markerDetails.getGreen() - 20 < 0 ? 0 : markerDetails.getGreen() - 20 ,markerDetails.getRed() - 20 < 0 ? 0 : markerDetails.getRed() - 20); //BGR
            Scalar hsv_max = new Scalar(markerDetails.getBlue()/2 + 20 < 0 ? 0 : markerDetails.getBlue()/2 + 20,markerDetails.getGreen() + 20 < 0 ? 0 : markerDetails.getGreen() + 20 ,markerDetails.getRed() + 20 < 0 ? 0 : markerDetails.getRed() + 20); //BGR

            double[] data = new double[3];
            if (!capture.isOpened()) {
                System.err.println("Can't read video properly.");
                return;
            }
            while (true) {
                capture.read(frame);
                if (!frame.empty()) {
                    // One way to select a range of colors by Hue
                    Imgproc.cvtColor(frame, hsv, Imgproc.COLOR_BGR2HSV);
                    Core.inRange(hsv, hsv_min, hsv_max, threshold);
                    Imgproc.erode(threshold, threshold, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8, 8)));
                    Imgproc.dilate(threshold, threshold, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8, 8)));

                    // Notice that the thresholds don't really work as a "distance"
                    // Ideally we would like to cut the image by hue and then pick just
                    // the area where S combined V are largest.
                    // Strictly speaking, this would be something like sqrt((255-S)^2+(255-V)^2)>Range
                    // But if we want to be "faster" we can do just (255-S)+(255-V)>Range
                    // Or otherwise 510-S-V>Range
                    // Anyhow, we do the following... Will see how fast it goes...
                    Core.split(hsv, hsvList); // We get 3 1D one channel Mats
                    Mat S = hsvList.get(1);
                    Mat V = hsvList.get(2);
                    Core.subtract(array255, S, S);
                    Core.subtract(array255, V, V);
                    S.convertTo(S, CvType.CV_32F);
                    V.convertTo(V, CvType.CV_32F);
                    Core.magnitude(S, V, distance);
                    //TODO: threshold2
                        Core.inRange(distance, new Scalar(0.0), new Scalar(200.0), threshold2);
                        Core.bitwise_and(threshold, threshold2, threshold);
                    // Apply the Hough Transform to find the circles
                    Imgproc.GaussianBlur(threshold, threshold, new Size(9, 9), 0, 0);
                    List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
                    Imgproc.HoughCircles(threshold, circles, Imgproc.CV_HOUGH_GRADIENT, 2, threshold.height() / 8, 200, 100, 0, 0);
                    //TODO: threshold2
                    Imgproc.findContours(threshold, contours, threshold2, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
                    Imgproc.drawContours(frame, contours, -1, new Scalar(255, 0, 0), 2);
                    System.out.println(contours.size());
                    Imgproc.Canny(threshold, threshold, 500, 250);

                    //-- 4. Add some info to the image
                    Imgproc.line(frame, new org.opencv.core.Point(150, 50), new org.opencv.core.Point(202, 200), new Scalar(100, 10, 10), 3);
    //                Imgproc.rectangle(frame, new org.opencv.core.Point(150, 50), new org.opencv.core.Point(202, 200), new Scalar(100, 10, 10), 3);
                    Imgproc.circle(frame, new org.opencv.core.Point(210, 210), 10, new Scalar(100, 10, 10), 3);
                    data = frame.get(210, 210);
                    Imgproc.putText(frame, String.format("(" + String.valueOf(data[0]) + "," + String.valueOf(data[1]) + "," + String.valueOf(data[2]) + ")"),
                            new org.opencv.core.Point(30, 30), 3, 1.0, new Scalar(100, 10, 10, 255), 3);
                    //Display the image
                    displayTrackInVideo();
                } else {
                    System.err.println(" -- No captured frame -- Break!");
                    break;
                }
            }

        }

private void initializeJFrames() {
        videoFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        videoFrame.setSize(640, 480);
        videoFrame.setBounds(0, 0, videoFrame.getWidth(), videoFrame.getHeight());
        videoFrame.setContentPane(videoPanel);
        videoFrame.setVisible(true);
        hsvFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        hsvFrame.setSize(640, 480);
        hsvFrame.setBounds(300, 100, hsvFrame.getWidth() + 300, 100 + hsvFrame.getHeight());
        hsvFrame.setContentPane(hsvPanel);
        hsvFrame.setVisible(true);
        thresholdFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        thresholdFrame.setSize(640, 480);
        thresholdFrame.setBounds(900, 300, hsvFrame.getWidth() + 900, 300 + hsvFrame.getHeight());
        thresholdFrame.setContentPane(thresholdPanel);
        thresholdFrame.setVisible(true);
    }

private void addClickEvent() {

        videoPanel.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent event) {
                //get the mouse location
                markerDetails.getMousePoint().setLocation(MouseInfo.getPointerInfo().getLocation());
                int rgb = videoPanel.matToBufferedImage(frame).getRGB(markerDetails.getX(), markerDetails.getY());
                Color color = new Color(rgb);
                markerDetails.setRed(color.getRed());
                markerDetails.setGreen(color.getGreen());
                markerDetails.setBlue(color.getBlue());
            }

            @Override
            public void mousePressed(MouseEvent e) {
            }

            @Override
            public void mouseReleased(MouseEvent e) {

            }

            @Override
            public void mouseEntered(MouseEvent e) {

            }

            @Override
            public void mouseExited(MouseEvent e) {

            }
        });
    }

private void displayTrackInVideo() {
            videoPanel.setimagewithMat(frame);
            hsvPanel.setimagewithMat(hsv);
            thresholdPanel.setimagewithMat(threshold);

            videoFrame.repaint();
            hsvFrame.repaint();
            thresholdFrame.repaint();
        }

as you can see, my problem is with the fields called hsv_min and hsv_max. I need to choose them correctly. So to do this, I added a click event on my panel, and took the exact color of the pixel of the marker that is on the wheel.

the code to my Pixel class is:

import java.awt.*;

public class Pixel {
    private final Point mousePoint;
    private int red;
    private int green;
    private int blue;

    public Pixel(){
        mousePoint = new Point();
    }

    public int getX(){
        return mousePoint.x;
    }
    public int getY(){
        return mousePoint.y;
    }

    public Point getMousePoint() {
        return mousePoint;
    }

    public int getRed() {
        return red;
    }

    public void setRed(int red) {
        this.red = red;
    }

    public int getGreen() {
        return green;
    }

    public void setGreen(int green) {
        this.green = green;
    }

    public int getBlue() {
        return blue;
    }

    public void setBlue(int blue) {
        this.blue = blue;
    }
}
Rick M.
  • 3,045
  • 1
  • 21
  • 39
Tal Ohana
  • 21
  • 3

0 Answers0