使用 C++ 从 Raspberry Pi 相机显示到 Raspberry Pi HDMI
Display to Raspberry Pi HDMI From Raspberry Pi Camera using C++
问题:如何将 Raspberry Pi 摄像头的视频流写入 HDMI 连接的显示器?
答案:见下文
我的系统:Raspberry Pi3,RaspbianJessie 发行版
VisualGDB 和 VisualStudio 2015
我花了几个小时将来自不同帖子的各种测试代码放在一起,我发布了这个编译后的测试代码供社区使用。它以 ~ 15fps 和 1200x720p 彩色视频输出工作。
https://visualgdb.com/tutorials/raspberry/camera/
注意事项:
VisualGDB 在 Sysroot 同步方面存在一些问题,当我 运行 来自 Visual Studio 的 built-in 操作时,它复制了一堆大小为 0 的 headers。相反,我手动复制了 /opt/vc
文件夹直接C:\SysGCC\raspberry\arm-linux-gnueabihf\sysroot
我还必须将 libbcm_host.so
(连同链接教程中的 libraspicam.so.0.1
)从 /opt/vc/lib
复制到本地 build/Debug/src
文件夹,
并在includes中添加=/opt/vc/include
(=表示本地sysroom目录)
bcm_host
库名称。
注意 2:Raspbian 发行版或编译器不喜欢 while(1)
循环,因此如果您将用于绘制框架的 for(...)
循环替换为 while(1)
而没有任何退出条件,你会得到一个黑屏输出。可能的原因是优化器,好的做法是完全避免没有退出条件的无限循环。
注意3:如果使用HDMI 输出来监控分辨率小于1280x720(小于摄像头视频流),可能会出现一些问题,找人编辑小屏幕的代码。具有复合视频输出的旧版本 RPi 也未经过测试。
谢谢,
#include <stdio.h>
#include <syslog.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "interface\vmcs_host\vc_dispmanx_types.h"
#include <bcm_host.h>
#include "raspicam.h"
#include <iostream>
typedef struct
{
DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T info;
void *image;
DISPMANX_UPDATE_HANDLE_T update;
DISPMANX_RESOURCE_HANDLE_T resource;
DISPMANX_ELEMENT_HANDLE_T element;
uint32_t vc_image_ptr;
} RECT_VARS_T;
int main(int argc, char **argv)
{
RECT_VARS_T vars;
VC_RECT_T src_rect;
VC_RECT_T dst_rect;
VC_DISPMANX_ALPHA_T alpha = {
static_cast<DISPMANX_FLAGS_ALPHA_T>(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS),
255, /*alpha 0->255*/
0
};
bcm_host_init();
vars.display = vc_dispmanx_display_open(0);
vc_dispmanx_display_get_info(vars.display, &vars.info);
//Grab Camera feed
raspicam::RaspiCam v_camera; //camera object
//Open camera
std::cout << "Opening Camera..." << std::endl;
if (!v_camera.open())
{
std::cerr << "Error opening camera" << std::endl;
return -1;
}
//may need to wait a while until camera stabilizes
int cam_width = v_camera.getWidth();
int cam_height = v_camera.getHeight();
vars.image = calloc(1, cam_width * cam_height * 3);
vars.resource = vc_dispmanx_resource_create( VC_IMAGE_RGB888,
cam_width,
cam_height,
&vars.vc_image_ptr);
vc_dispmanx_rect_set(&dst_rect, 0, 0, cam_width, cam_height);
vars.update = vc_dispmanx_update_start(10);
vars.element = vc_dispmanx_element_add( vars.update,
vars.display,
2000, // layer
&dst_rect,
vars.resource,
&src_rect, //may not need this
DISPMANX_PROTECTION_NONE,
&alpha,
NULL, // clamp
static_cast<DISPMANX_TRANSFORM_T>(0));
//Draw 50 frames to screen
for (int i = 0; i < 50; i++)
{
vc_dispmanx_resource_write_data( vars.resource,
VC_IMAGE_RGB888,
cam_width * 3,
vars.image,
&dst_rect);
unsigned char* fbp = static_cast<unsigned char*>(vars.image);
v_camera.grab();
v_camera.retrieve(fbp, raspicam::RASPICAM_FORMAT_RGB);//get camera image
vc_dispmanx_update_submit_sync(vars.update);
}
int ret = vc_dispmanx_resource_delete(vars.resource);
vc_dispmanx_display_close(vars.display);
return true;
}
如果要进行任何图像处理,直接在循环中使用fbp
指针写入即可,例如(不是最有效的方法)
int location_cam = 0;
for (int x = 200; x < 300; x++)
{
for (int y = 200; y < 300; y++)
{
location_cam = (x) * (3) + (y) * cam_width * 3;
*(fbp + location_cam) = 255; //red
*(fbp + location_cam + 1) = 0; //green
*(fbp + location_cam + 2) = 0; //blue
}
}
问题:如何将 Raspberry Pi 摄像头的视频流写入 HDMI 连接的显示器?
答案:见下文
我的系统:Raspberry Pi3,RaspbianJessie 发行版 VisualGDB 和 VisualStudio 2015
我花了几个小时将来自不同帖子的各种测试代码放在一起,我发布了这个编译后的测试代码供社区使用。它以 ~ 15fps 和 1200x720p 彩色视频输出工作。
https://visualgdb.com/tutorials/raspberry/camera/
注意事项:
VisualGDB 在 Sysroot 同步方面存在一些问题,当我 运行 来自 Visual Studio 的 built-in 操作时,它复制了一堆大小为 0 的 headers。相反,我手动复制了 /opt/vc
文件夹直接C:\SysGCC\raspberry\arm-linux-gnueabihf\sysroot
我还必须将 libbcm_host.so
(连同链接教程中的 libraspicam.so.0.1
)从 /opt/vc/lib
复制到本地 build/Debug/src
文件夹,
并在includes中添加=/opt/vc/include
(=表示本地sysroom目录)
bcm_host
库名称。
注意 2:Raspbian 发行版或编译器不喜欢 while(1)
循环,因此如果您将用于绘制框架的 for(...)
循环替换为 while(1)
而没有任何退出条件,你会得到一个黑屏输出。可能的原因是优化器,好的做法是完全避免没有退出条件的无限循环。
注意3:如果使用HDMI 输出来监控分辨率小于1280x720(小于摄像头视频流),可能会出现一些问题,找人编辑小屏幕的代码。具有复合视频输出的旧版本 RPi 也未经过测试。
谢谢,
#include <stdio.h>
#include <syslog.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "interface\vmcs_host\vc_dispmanx_types.h"
#include <bcm_host.h>
#include "raspicam.h"
#include <iostream>
typedef struct
{
DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T info;
void *image;
DISPMANX_UPDATE_HANDLE_T update;
DISPMANX_RESOURCE_HANDLE_T resource;
DISPMANX_ELEMENT_HANDLE_T element;
uint32_t vc_image_ptr;
} RECT_VARS_T;
int main(int argc, char **argv)
{
RECT_VARS_T vars;
VC_RECT_T src_rect;
VC_RECT_T dst_rect;
VC_DISPMANX_ALPHA_T alpha = {
static_cast<DISPMANX_FLAGS_ALPHA_T>(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS),
255, /*alpha 0->255*/
0
};
bcm_host_init();
vars.display = vc_dispmanx_display_open(0);
vc_dispmanx_display_get_info(vars.display, &vars.info);
//Grab Camera feed
raspicam::RaspiCam v_camera; //camera object
//Open camera
std::cout << "Opening Camera..." << std::endl;
if (!v_camera.open())
{
std::cerr << "Error opening camera" << std::endl;
return -1;
}
//may need to wait a while until camera stabilizes
int cam_width = v_camera.getWidth();
int cam_height = v_camera.getHeight();
vars.image = calloc(1, cam_width * cam_height * 3);
vars.resource = vc_dispmanx_resource_create( VC_IMAGE_RGB888,
cam_width,
cam_height,
&vars.vc_image_ptr);
vc_dispmanx_rect_set(&dst_rect, 0, 0, cam_width, cam_height);
vars.update = vc_dispmanx_update_start(10);
vars.element = vc_dispmanx_element_add( vars.update,
vars.display,
2000, // layer
&dst_rect,
vars.resource,
&src_rect, //may not need this
DISPMANX_PROTECTION_NONE,
&alpha,
NULL, // clamp
static_cast<DISPMANX_TRANSFORM_T>(0));
//Draw 50 frames to screen
for (int i = 0; i < 50; i++)
{
vc_dispmanx_resource_write_data( vars.resource,
VC_IMAGE_RGB888,
cam_width * 3,
vars.image,
&dst_rect);
unsigned char* fbp = static_cast<unsigned char*>(vars.image);
v_camera.grab();
v_camera.retrieve(fbp, raspicam::RASPICAM_FORMAT_RGB);//get camera image
vc_dispmanx_update_submit_sync(vars.update);
}
int ret = vc_dispmanx_resource_delete(vars.resource);
vc_dispmanx_display_close(vars.display);
return true;
}
如果要进行任何图像处理,直接在循环中使用fbp
指针写入即可,例如(不是最有效的方法)
int location_cam = 0;
for (int x = 200; x < 300; x++)
{
for (int y = 200; y < 300; y++)
{
location_cam = (x) * (3) + (y) * cam_width * 3;
*(fbp + location_cam) = 255; //red
*(fbp + location_cam + 1) = 0; //green
*(fbp + location_cam + 2) = 0; //blue
}
}