在java opencv中显示来自jpanel网格中多个摄像头的视频流

时间:2021-10-27 11:31:36

My current code for grid to show video stream is as follow

我目前用于显示视频流的网格代码如下

//Function for displaying grid window//
public void createMap(int maxX, int maxY) {
    gameGrid = new JPanel(new GridLayout(maxX, maxY, 1, 1));
    gameGrid.setBackground(Color.GREEN);
    for (int i = 0; i < maxX; i++) {

        for (int j = 0; j < maxY; j++) {
            JPanel panel = new JPanel();
            panel.setPreferredSize(PREF_SIZE);
            String name = String.format("[%d, %d]", i, j);
            panel.setName(name);
            panel.setBackground(Color.black);

            gameGrid.add(panel);
        }
    }
}

I call this function as createMap(2,2) so it create grid for 2x2(4 window). I want to show video stream in each of these grid. I receiving the video stream through 4 cctv cameras attached with DVR. I used following code for Showing video streams using opencv

我将此函数称为createMap(2,2),因此它为2x2(4窗口)创建网格。我想在每个网格中显示视频流。我通过附带DVR的4个闭路电视摄像机接收视频流。我使用以下代码使用opencv显示视频流

package cctvmonitorsystem;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;

// DB connectivity classes
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.SQLException;
import java.sql.ResultSet;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;
import org.opencv.highgui.VideoCapture;
import org.opencv.imgproc.Imgproc;

import java.util.Arrays;

public class Video {
    public static void main(String args[]) throws SQLException {
        int maxCamNo = 4;
        //create connection
        DbConnect dbcon = new DbConnect();
        Connection con = dbcon.openCon();        
        Statement stmt = con.createStatement();

        String getDevice="select * from device order by d_id limit 1";
        ResultSet res=stmt.executeQuery(getDevice);

        // DECLARE VARIABLES FOR DEVICE ADDRESS & PORT
        String devAddress = null;
        int httpPort=0;

        while (res.next())
        {
            devAddress=res.getString("d_address");
            httpPort=res.getInt("d_http_port");
        }

        dbcon.closeCon(con); // Connection closed

        VideoCapture vcam[] = new VideoCapture[maxCamNo];

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        for (int i = 0; i < vcam.length; i++) {
            try {
                vcam[i] = new VideoCapture();
                vcam[i].open("http://"+devAddress+":"+httpPort+"/cgi-bin/view.cgi?chn=" + i + "&u=admin&p=");
                //vcam[i]=new VideoCapture(i);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!vcam[i].isOpened()) {
                System.out.println("Camera " + i + " error");
            }
        }

        AccessVideo av = new AccessVideo(vcam);

        //Initialize swing components
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(av);
        //frame.setSize(1024,768);  
        frame.setMaximumSize(null);
        frame.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH);
        frame.setVisible(true);

        while (vcam[0].isOpened()) {
            av.repaint();
        }
    }
}

class AccessVideo extends JPanel {

    VideoCapture[] camera = new VideoCapture[6];

    AccessVideo(VideoCapture[] camView) {
        camera = camView;
    }

    public BufferedImage Mat2BufferedImage(Mat m) {
        System.out.println("Channels - "+m.channels());
        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 img = new BufferedImage(m.cols(), m.rows(), type);
        final byte[] targetPixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
        System.arraycopy(b, 0, targetPixels, 0, b.length);
        return img;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Mat[] mat = new Mat[camera.length];

        int width=400;
        int height=300;
        int xpos = 0;
        int ypos = 0;
        int y = 1;
        for (int i = 0; i < camera.length; i++) {
            mat[i] = new Mat();

            camera[i].read(mat[i]);
            BufferedImage image = Mat2BufferedImage(mat[i]);
            g.drawImage(image, xpos, ypos, width, height, null);
            xpos = xpos + width;
            if (y == 3) {
                xpos = 0;
                ypos = ypos + height;
                y = 0;
            }
            y++;
        }
    }
}

Here the video streams will show according to x & y co-ordinates. But I want to show these video streams in grids which i mention above. Can anyone help me to resolve this issue.

这里的视频流将根据x&y坐标显示。但我想在上面提到的网格中显示这些视频流。任何人都可以帮我解决这个问题。

2 个解决方案

#1


I did something similar here is my code, but this is hardcoded to only 6 cameras.

我在这里做了类似的事情是我的代码,但这只是硬编码到6个摄像头。

This is the main function where I called the addComponentsToPane.

这是我调用addComponentsToPane的主要功能。

public static void main(String[] args) {
    CamtestMonitor f = new CamtestMonitor("Monitor");

    f.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    });

    //Set up the content pane.
    f.addComponentsToPane(f.getContentPane());
    //Display the window.
    f.pack();
    f.setVisible(true);
}

This is the addComponentsToPane function where we add 6 different ServerUI's. Each one extends the JLabel class and implements DataListener.

这是addComponentsToPane函数,我们在其中添加了6个不同的ServerUI。每一个都扩展了JLabel类并实现了DataListener。

public void addComponentsToPane(final Container pane) {
    final JPanel jp = new JPanel();
    jp.setLayout(gl);

    //Set up components preferred size
    jp.add(new ServerUI(8880));
    jp.add(new ServerUI(8891));
    jp.add(new ServerUI(8892));
    jp.add(new ServerUI(8893));
    jp.add(new ServerUI(8894));
    jp.add(new ServerUI(8895));
    jp.setPreferredSize(new Dimension(1600, 900));

    //Set up the horizontal gap value
    gl.setHgap(gapSize);
    //Set up the vertical gap value
    gl.setVgap(gapSize);
    //Set up the layout of the buttons
    gl.layoutContainer(jp);

    pane.add(jp, BorderLayout.NORTH);
    pane.add(new JSeparator(), BorderLayout.SOUTH);
}

There you have the Constructor of the ServerUI:

你有ServerUI的构造函数:

public ServerUI(int port) {
    SocketServer server = new SocketServer(port);
    server.setOnDataListener(this);
    server.start();
}

Finally, here we have the overrrided function that refresh the image on each JLabel.

最后,这里我们有覆盖函数刷新每个JLabel上的图像。

@Override
public void paint(Graphics g) {
    synchronized (queue) {
        if (queue.size() > 0) {
            lastFrame = queue.poll();
        }
    }
    if (lastFrame != null) {
        g.drawImage(lastFrame, 0, 0, null);
    } 
}

#2


You can have one thread for each camera, and also you extend JPanel class and override the paintComponent() method, like example below

每个摄像头可以有一个线程,还可以扩展JPanel类并覆盖paintComponent()方法,如下例所示

public class MyJPanel extends JPanel {
    private BufferedImage image;

    public MyJPanel() {
        super();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        if (image != null) {
            g2.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), this);
        }
    }

    public void refresh(BufferedImage image) {
        this.image = image;
        this.repaint();
    }
}

public class CameraHandler implements Runnable {
   VideoCapture vCapture;
   MyJPanel mPanel;
   public CameraHandler(VideoCapture vCapture, MyJPanel mPanel) {
      this.vCapture = vCapture;
      this.mPanel = mPanel;
   }

   public void run() {
      while(vCapture.canReadFrame...) {
         then convert the Mat to BufferedImage;
         then call this:
         mPanel.refresh(convertedImage);
      }
   }

}

public class MainClass {

   public static void main(String[] args) {
       VideoCapture vcam[] = new VideoCapture[maxCamNo];

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        for (int i = 0; i < vcam.length; i++) {
            try {
                vcam[i] = new VideoCapture();
                vcam[i].open("http://"+devAddress+":"+httpPort+"/cgi-bin/view.cgi?chn=" + i + "&u=admin&p=");
                //vcam[i]=new VideoCapture(i);
                if(vcam[i].isOpen) {
                   new Thread(new CameraHandler(vcam[i], and you MyJPanel reference)).start();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!vcam[i].isOpened()) {
                System.out.println("Camera " + i + " error");
            }
        }
   }

}

The code above is just an example to show the way, if you use this then need to arrange the code as your need. Hope this code help you!

上面的代码只是一个显示方式的示例,如果您使用它,则需要根据需要安排代码。希望这段代码能帮到你!

#1


I did something similar here is my code, but this is hardcoded to only 6 cameras.

我在这里做了类似的事情是我的代码,但这只是硬编码到6个摄像头。

This is the main function where I called the addComponentsToPane.

这是我调用addComponentsToPane的主要功能。

public static void main(String[] args) {
    CamtestMonitor f = new CamtestMonitor("Monitor");

    f.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    });

    //Set up the content pane.
    f.addComponentsToPane(f.getContentPane());
    //Display the window.
    f.pack();
    f.setVisible(true);
}

This is the addComponentsToPane function where we add 6 different ServerUI's. Each one extends the JLabel class and implements DataListener.

这是addComponentsToPane函数,我们在其中添加了6个不同的ServerUI。每一个都扩展了JLabel类并实现了DataListener。

public void addComponentsToPane(final Container pane) {
    final JPanel jp = new JPanel();
    jp.setLayout(gl);

    //Set up components preferred size
    jp.add(new ServerUI(8880));
    jp.add(new ServerUI(8891));
    jp.add(new ServerUI(8892));
    jp.add(new ServerUI(8893));
    jp.add(new ServerUI(8894));
    jp.add(new ServerUI(8895));
    jp.setPreferredSize(new Dimension(1600, 900));

    //Set up the horizontal gap value
    gl.setHgap(gapSize);
    //Set up the vertical gap value
    gl.setVgap(gapSize);
    //Set up the layout of the buttons
    gl.layoutContainer(jp);

    pane.add(jp, BorderLayout.NORTH);
    pane.add(new JSeparator(), BorderLayout.SOUTH);
}

There you have the Constructor of the ServerUI:

你有ServerUI的构造函数:

public ServerUI(int port) {
    SocketServer server = new SocketServer(port);
    server.setOnDataListener(this);
    server.start();
}

Finally, here we have the overrrided function that refresh the image on each JLabel.

最后,这里我们有覆盖函数刷新每个JLabel上的图像。

@Override
public void paint(Graphics g) {
    synchronized (queue) {
        if (queue.size() > 0) {
            lastFrame = queue.poll();
        }
    }
    if (lastFrame != null) {
        g.drawImage(lastFrame, 0, 0, null);
    } 
}

#2


You can have one thread for each camera, and also you extend JPanel class and override the paintComponent() method, like example below

每个摄像头可以有一个线程,还可以扩展JPanel类并覆盖paintComponent()方法,如下例所示

public class MyJPanel extends JPanel {
    private BufferedImage image;

    public MyJPanel() {
        super();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        if (image != null) {
            g2.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), this);
        }
    }

    public void refresh(BufferedImage image) {
        this.image = image;
        this.repaint();
    }
}

public class CameraHandler implements Runnable {
   VideoCapture vCapture;
   MyJPanel mPanel;
   public CameraHandler(VideoCapture vCapture, MyJPanel mPanel) {
      this.vCapture = vCapture;
      this.mPanel = mPanel;
   }

   public void run() {
      while(vCapture.canReadFrame...) {
         then convert the Mat to BufferedImage;
         then call this:
         mPanel.refresh(convertedImage);
      }
   }

}

public class MainClass {

   public static void main(String[] args) {
       VideoCapture vcam[] = new VideoCapture[maxCamNo];

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        for (int i = 0; i < vcam.length; i++) {
            try {
                vcam[i] = new VideoCapture();
                vcam[i].open("http://"+devAddress+":"+httpPort+"/cgi-bin/view.cgi?chn=" + i + "&u=admin&p=");
                //vcam[i]=new VideoCapture(i);
                if(vcam[i].isOpen) {
                   new Thread(new CameraHandler(vcam[i], and you MyJPanel reference)).start();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!vcam[i].isOpened()) {
                System.out.println("Camera " + i + " error");
            }
        }
   }

}

The code above is just an example to show the way, if you use this then need to arrange the code as your need. Hope this code help you!

上面的代码只是一个显示方式的示例,如果您使用它,则需要根据需要安排代码。希望这段代码能帮到你!