简体   繁体   English

使用OpenCV从IP摄像机流式传输

[英]Streaming from IP camera using OpenCV

I'm using OpenCV to process a camera image, however, at the moment I'm using a USB webcam that is connected to my computer. 我正在使用OpenCV处理相机图像,但是,此刻,我正在使用连接到计算机的USB网络摄像头。 I was wondering if it is possible to make changes to my current code to stream a video from an IP address. 我想知道是否可以更改当前代码以从IP地址流式传输视频。

startCamera method opens up the camera. startCamera方法打开相机。

Code: 码:

public class ObjRecognitionController {
// FXML camera button
@FXML
private Button cameraButton;
// the FXML area for showing the current frame
@FXML
private ImageView originalFrame;
// the FXML area for showing the mask
@FXML
private ImageView maskImage;
// the FXML area for showing the output of the morphological operations
@FXML
private ImageView morphImage;
// FXML slider for setting HSV ranges
@FXML
private Slider hueStart;
@FXML
private Slider hueStop;
@FXML
private Slider saturationStart;
@FXML
private Slider saturationStop;
@FXML
private Slider valueStart;
@FXML
private Slider valueStop;
// FXML label to show the current values set with the sliders
@FXML
private Label hsvCurrentValues;

// a timer for acquiring the video stream
private ScheduledExecutorService timer;
// the OpenCV object that performs the video capture
private VideoCapture capture = new VideoCapture();
// a flag to change the button behavior
private boolean cameraActive;

// property for object binding
private ObjectProperty<String> hsvValuesProp;

/**
 * The action triggered by pushing the button on the GUI
 */
@FXML
private void startCamera()
{
    // bind a text property with the string containing the current range of
    // HSV values for object detection
    hsvValuesProp = new SimpleObjectProperty<>();
    this.hsvCurrentValues.textProperty().bind(hsvValuesProp);

    // set a fixed width for all the image to show and preserve image ratio
    this.imageViewProperties(this.originalFrame, 400);
    this.imageViewProperties(this.maskImage, 200);
    this.imageViewProperties(this.morphImage, 200);

    if (!this.cameraActive) {
        // start the video capture
        this.capture.open(0);

        // is the video stream available?
        if (this.capture.isOpened()) {
            this.cameraActive = true;

            // grab a frame every 33 ms (30 frames/sec)
            Runnable frameGrabber = new Runnable() {

                @Override
                public void run() {
                    Image imageToShow = grabFrame();
                    originalFrame.setImage(imageToShow);
                }
            };

            this.timer = Executors.newSingleThreadScheduledExecutor();
            this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);

            // update the button content
            this.cameraButton.setText("Stop Camera");
        } else {
            // log the error
            System.err.println("Failed to open the camera connection...");
        }
    } else {
        // the camera is not active at this point
        this.cameraActive = false;
        // update again the button content
        this.cameraButton.setText("Start Camera");

        // stop the timer
        try {
            this.timer.shutdown();
            this.timer.awaitTermination(33, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            // log the exception
            System.err.println("Exception in stopping the frame capture, trying to release the camera now... " + e);
        }

        // release the camera
        this.capture.release();
    }
}

/**
 * Get a frame from the opened video stream (if any)
 * 
 * @return the {@link Image} to show
 */
private Image grabFrame()
{
    // init everything
    Image imageToShow = null;
    Mat frame = new Mat();

    // check if the capture is open
    if (this.capture.isOpened())
    {
        try
        {
            // read the current frame
            this.capture.read(frame);

            // if the frame is not empty, process it
            if (!frame.empty())
            {
                // init
                Mat blurredImage = new Mat();
                Mat hsvImage = new Mat();
                Mat mask = new Mat();
                Mat morphOutput = new Mat();

                // remove some noise
                Imgproc.blur(frame, blurredImage, new Size(7, 7));

                // convert the frame to HSV
                Imgproc.cvtColor(blurredImage, hsvImage, Imgproc.COLOR_BGR2HSV);

                // get thresholding values from the UI
                // remember: H ranges 0-180, S and V range 0-255
                Scalar minValues = new Scalar(this.hueStart.getValue(), this.saturationStart.getValue(),
                        this.valueStart.getValue());
                Scalar maxValues = new Scalar(this.hueStop.getValue(), this.saturationStop.getValue(),
                        this.valueStop.getValue());

                // show the current selected HSV range
                String valuesToPrint = "Hue range: " + minValues.val[0] + "-" + maxValues.val[0]
                        + "\tSaturation range: " + minValues.val[1] + "-" + maxValues.val[1] + "\tValue range: "
                        + minValues.val[2] + "-" + maxValues.val[2];
                this.onFXThread(this.hsvValuesProp, valuesToPrint);

                // threshold HSV image to select tennis balls
                Core.inRange(hsvImage, minValues, maxValues, mask);
                // show the partial output
                this.onFXThread(this.maskImage.imageProperty(), this.mat2Image(mask));

                // morphological operators
                // dilate with large element, erode with small ones
                Mat dilateElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(24, 24));
                Mat erodeElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(12, 12));

                Imgproc.erode(mask, morphOutput, erodeElement);
                Imgproc.erode(mask, morphOutput, erodeElement);

                Imgproc.dilate(mask, morphOutput, dilateElement);
                Imgproc.dilate(mask, morphOutput, dilateElement);

                // show the partial output
                this.onFXThread(this.morphImage.imageProperty(), this.mat2Image(morphOutput));

                // find the tennis ball(s) contours and show them
                frame = this.findAndDrawBalls(morphOutput, frame);

                // convert the Mat object (OpenCV) to Image (JavaFX)
                imageToShow = mat2Image(frame);
            }

        }
        catch (Exception e)
        {
            // log the (full) error
            System.err.print("ERROR");
            e.printStackTrace();
        }
    }

    return imageToShow;
}

/**
 * Given a binary image containing one or more closed surfaces, use it as a
 * mask to find and highlight the objects contours
 * 
 * @param maskedImage
 *            the binary image to be used as a mask
 * @param frame
 *            the original {@link Mat} image to be used for drawing the
 *            objects contours
 * @return the {@link Mat} image with the objects contours framed
 */
private Mat findAndDrawBalls(Mat maskedImage, Mat frame) {
    // init
    List<MatOfPoint> contours = new ArrayList<>();
    Mat hierarchy = new Mat();
    // find contours
    Imgproc.findContours(maskedImage, contours, hierarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE);

    // if any contour exist...
    if (hierarchy.size().height > 0 && hierarchy.size().width > 0) {
        // for each contour, display it in yellow
        for (int idx = 0; idx >= 0; idx = (int) hierarchy.get(0, idx)[0]) {
            Imgproc.drawContours(frame, contours, idx, new Scalar(0, 255, 255),2);

            Rect rect = Imgproc.boundingRect(contours.get(idx));

            if(rect.x < 25){
                System.out.println("Turn left " + rect.x);
            }else if(rect.x > 600){
                System.out.println("Turn Right: " + rect.x);
            }
            System.out.println();
        }
    }

    return frame;
}

/**
 * Set typical {@link ImageView} properties: a fixed width and the
 * information to preserve the original image ration
 * 
 * @param image
 *            the {@link ImageView} to use
 * @param dimension
 *            the width of the image to set
 */
private void imageViewProperties(ImageView image, int dimension) {
    // set a fixed width for the given ImageView
    image.setFitWidth(dimension);
    // preserve the image ratio
    image.setPreserveRatio(true);
}

/**
 * Convert a {@link Mat} object (OpenCV) in the corresponding {@link Image}
 * for JavaFX
 * 
 * @param frame
 *            the {@link Mat} representing the current frame
 * @return the {@link Image} to show
 */
private Image mat2Image(Mat frame) {
    // create a temporary buffer
    MatOfByte buffer = new MatOfByte();
    // encode the frame in the buffer, according to the PNG format
    Imgcodecs.imencode(".png", frame, buffer);
    // build and return an Image created from the image encoded in the
    // buffer
    return new Image(new ByteArrayInputStream(buffer.toArray()));
}

/**
 * Generic method for putting element running on a non-JavaFX thread on the
 * JavaFX thread, to properly update the UI
 * 
 * @param property
 *            a {@link ObjectProperty}
 * @param value
 *            the value to set for the given {@link ObjectProperty}
 */
private <T> void onFXThread(final ObjectProperty<T> property, final T value)
{
    Platform.runLater(new Runnable() {

        @Override
        public void run()
        {
            property.set(value);
        }
    });
}

} }

Camera Documentation 相机说明文件

VLC Media Player VLC Media Player is a cross-platform video player, streaming server and converter solution in a single package. VLC Media Player VLC Media Player是一个跨平台的视频播放器,流服务器和转换器解决方案,位于一个软件包中。 Get it here. 在这里获取。

For using IP Webcam with VLC media player, in its menu select Media ⇨ Open Network Stream and enter http://192.168.1.8:8080/video for streaming video or http://192.168.1.8:8080/audio.wav for streaming audio. 对于使用IP网络摄像头使用VLC媒体播放器,在菜单上选择媒体⇨打开网络流和输入http://192.168.1.8:8080/video为视频流或http://192.168.1.8:8080/audio.wav流媒体音频。

You can also use VLC Media player for video recording: 您也可以使用VLC Media Player进行视频录制:

Select Media -> Convert/Save. 选择媒体->转换/保存。 Select Network tab Enter http://192.168.1.8:8080/video as URL Click convert/save Select destination file, format in which you want to save and you're good to go ZoneMinder Use this configuration: 选择“网络”选项卡输入http://192.168.1.8:8080/video作为URL单击“转换/保存”。选择目标文件,选择要保存的格式, 最好使用ZoneMinder使用以下配置:

General: Source type: Remote Function: Monitor 常规:信号源类型:远程功能:监控器

Source: Protocol: HTTP Method: Simple Host name: 192.168.1.8 Port: 8080 Remote host path: /video (just "video" doesn't work). 源:协议:HTTP方法:简单主机名:192.168.1.8端口:8080远程主机路径:/ video(仅“ video”不起作用)。

Note: If necessary, specify your username in password in URL, like this: username:password@192.168.1.8. 注意:如有必要,请在URL的密码中指定用户名,例如:username:password@192.168.1.8。

Blue Iris Open "Add camera" dialog as usual 蓝色虹膜照常打开“添加相机”对话框

When using IP Webcam, you have to pick "MJPEG Stream" from the list instead of a specific camera. 使用IP网络摄像头时,必须从列表中选择“ MJPEG流”,而不是特定的摄像机。

Video path: /video Audio path: /audio.wav Host name: 192.168.1.8 Port: 8080 It doesn't matter what you enter into "RTSP/video port" box. 视频路径:/ video音频路径:/audio.wav主机名:192.168.1.8端口:8080在“ RTSP /视频端口”框中输入任何内容都没有关系。

webcamXP In webcamXP main interface, right click on video source and select Network cameras ⇨ Connect... webcamXP在webcamXP主界面中,右键单击视频源,然后选择网络摄像机⇨连接...

Set Camera Brand to Android and Camera Model to IP Webcam. 将“摄像机品牌”设置为Android,将“摄像机型号”设置为IP Webcam。 Select desired preset (MJPEG recommended). 选择所需的预设(建议使用MJPEG)。 Click Next. 点击下一步。

Set Hostname to 192.168.1.8 and Port to 8080. 将主机名设置为192.168.1.8并将端口设置为8080。

Click Ok, and you're ready to use your new camera! 单击确定,您就可以使用新相机了!

Advanced Here is the list of IP Webcam service URLs: 高级这是IP网络摄像头服务URL的列表:

http://192.168.1.8:8080/video is the MJPEG URL. http://192.168.1.8:8080/video是MJPEG URL。 http://192.168.1.8:8080/shot.jpg fetches the latest frame. http://192.168.1.8:8080/shot.jpg获取最新的帧。 http://192.168.1.8:8080/audio.wav is the audio stream in Wav format. http://192.168.1.8:8080/audio.wav是Wav格式的音频流。 http://192.168.1.8:8080/audio.aac is the audio stream in AAC format (if supported by hardware). http://192.168.1.8:8080/audio.aac是AAC格式的音频流(如果硬件支持)。 http://192.168.1.8:8080/audio.opus is the audio stream in Opus format. http://192.168.1.8:8080/audio.opus是Opus格式的音频流。 http://192.168.1.8:8080/focus focuses the camera. http://192.168.1.8:8080/focus聚焦相机。 http://192.168.1.8:8080/nofocus releases the focus. http://192.168.1.8:8080/nofocus释放焦点。

You can just modify 您可以修改

VideoCapture camera = new VideoCapture("IPADDRESS");

or 要么

capture.open("IPADRESS");

You have to capture the video from the stream url of the camera like 您必须从摄像机的流网址捕获视频,例如

VideoCapture capture = new VideoCapture(url);

The url can be 网址可以是

url = "http://IPADDRESS:PORT/?dummy=param.mjpg"
//or
url= "http://IPADDRESS:PORT/mjpeg.cgi";
//or
url = "http://IPADDRESS:PORT/mjpg/mjpeg.cgi";
//or
url ="http://IPADDRESS:PORT/video.mjpeg";

Try to confirm the correct values using your browser, Hope that helps. 尝试使用浏览器确认正确的值,希望对您有所帮助。

Also instead of using IP webcam App with OpenCV incase you are using an android device, A better alternative is to use droidcam app, and pc software to recognise the webcam like 另外 ,如果您使用的是Android设备,则不要在OpenCV中使用IP网络摄像头应用程序,更好的选择是使用droidcam应用程序和PC软件来识别网络摄像头,例如

VideoCapture capture = new VideoCapture(camIndex);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM