java 使用 OpenCV 从 IP 摄像机流式传输
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35940568/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Streaming from IP camera using OpenCV
提问by PRCube
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. I was wondering if it is possible to make changes to my current code to stream a video from an IP address.
我正在使用 OpenCV 处理相机图像,但是,目前我使用的是连接到我的计算机的 USB 网络摄像头。我想知道是否可以更改我当前的代码以从 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 PlayerVLC Media Player is a cross-platform video player, streaming server and converter solution in a single package. Get it here.
VLC 媒体播放器VLC 媒体播放器是一个跨平台的视频播放器、流媒体服务器和转换器解决方案。拿到这里。
For using IP Webcam with VLC media player, in its menu select Media ? Open Network Stream and enter http://192.168.1.8:8080/videofor streaming video or http://192.168.1.8:8080/audio.wavfor streaming audio.
要将 IP 网络摄像头与 VLC 媒体播放器一起使用,请在其菜单中选择媒体?打开 Network Stream 并输入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 媒体播放器进行视频录制:
Select Media -> Convert/Save. Select Network tab Enter http://192.168.1.8:8080/videoas URL Click convert/save Select destination file, format in which you want to save and you're good to go ZoneMinderUse 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(只是“视频”不起作用)。
Note: If necessary, specify your username in password in URL, like this: username:[email protected].
注意:如有必要,请在 URL 中的密码中指定您的用户名,例如:username:[email protected]。
Blue IrisOpen "Add camera" dialog as usual
Blue Iris像往常一样打开“添加相机”对话框
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/视频端口”框中输入什么并不重要。
webcamXPIn 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. Select desired preset (MJPEG recommended). Click Next.
将相机品牌设置为 Android,将相机型号设置为 IP 网络摄像头。选择所需的预设(推荐 MJPEG)。点击下一步。
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!
单击“确定”,您就可以使用新相机了!
AdvancedHere is the list of IP Webcam service URLs:
高级这是 IP 网络摄像头服务 URL 的列表:
http://192.168.1.8:8080/videois the MJPEG URL. http://192.168.1.8:8080/shot.jpgfetches the latest frame. http://192.168.1.8:8080/audio.wavis the audio stream in Wav format. http://192.168.1.8:8080/audio.aacis the audio stream in AAC format (if supported by hardware). http://192.168.1.8:8080/audio.opusis the audio stream in Opus format. http://192.168.1.8:8080/focusfocuses the camera. http://192.168.1.8:8080/nofocusreleases the focus.
http://192.168.1.8:8080/video是 MJPEG URL。 http://192.168.1.8:8080/shot.jpg获取最新帧。 http://192.168.1.8:8080/audio.wav是 Wav 格式的音频流。 http://192.168.1.8:8080/audio.aac是 AAC 格式的音频流(如果硬件支持)。 http://192.168.1.8:8080/audio.opus是 Opus 格式的音频流。 http://192.168.1.8:8080/focus聚焦相机。 http://192.168.1.8:8080/nofocus释放焦点。
回答by Adah
You can just modify
你可以修改
VideoCapture camera = new VideoCapture("IPADDRESS");
or
或者
capture.open("IPADRESS");
回答by Collins Abitekaniza
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.
尝试使用浏览器确认正确的值,希望有帮助。
Alsoinstead 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
另外,不要使用带有 OpenCV 的 IP 网络摄像头应用程序,如果您使用的是 android 设备,更好的选择是使用 droidcam 应用程序和 pc 软件来识别网络摄像头,例如
VideoCapture capture = new VideoCapture(camIndex);