Files
Loongson_2k0300_SmartCar/opencv_demo3/opencv_demo3.cpp
T

141 lines
4.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* @Author: ilikara 3435193369@qq.com
* @Date: 2025-01-07 06:26:01
* @LastEditors: ilikara 3435193369@qq.com
* @LastEditTime: 2025-01-07 08:10:45
* @FilePath: /smartcar/opencv_demo2/opencv_demo2.cpp
* @Description: 使用Haar级联分类器从USB摄像头获取图像,并将图像居中显示到160x128的RGB565 framebuffer设备
*/
#include <opencv2/opencv.hpp>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
using namespace cv;
using namespace std;
// 将 RGB888 转换为 RGB565
ushort rgb888_to_rgb565(const Vec3b &color)
{
return ((color[2] >> 3) << 11) | ((color[1] >> 2) << 5) | (color[0] >> 3);
}
int main()
{
// Framebuffer 设备
const char *fb_device = "/dev/fb0";
int fb_fd = open(fb_device, O_RDWR);
if (fb_fd == -1)
{
cerr << "Error: Cannot open framebuffer device" << endl;
return -1;
}
// 获取 Framebuffer 信息
struct fb_var_screeninfo vinfo;
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo))
{
cerr << "Error: Cannot get framebuffer information" << endl;
close(fb_fd);
return -1;
}
// 检查 Framebuffer 是否支持 RGB565
if (vinfo.bits_per_pixel != 16)
{
cerr << "Error: Framebuffer is not RGB565 format" << endl;
close(fb_fd);
return -1;
}
// 映射 Framebuffer 到内存
size_t fb_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
ushort *fb_data = (ushort *)mmap(0, fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
if (fb_data == MAP_FAILED)
{
cerr << "Error: Failed to map framebuffer to memory" << endl;
close(fb_fd);
return -1;
}
// 打开USB摄像头
VideoCapture cap(0); // 0表示第一个摄像头
if (!cap.isOpened())
{
cerr << "Error: Cannot open camera" << endl;
return -1;
}
// 设置摄像头参数
cap.set(CAP_PROP_FRAME_WIDTH, 640);
cap.set(CAP_PROP_FRAME_HEIGHT, 360);
cap.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'));
cap.set(CAP_PROP_AUTO_EXPOSURE, -1); // 启用自动曝光
// 加载Haar级联分类器
CascadeClassifier face_cascade;
if (!face_cascade.load("opencv/share/opencv4/haarcascades/haarcascade_frontalface_default.xml"))
{
cerr << "Error: Cannot load Haar cascade classifier" << endl;
return -1;
}
// 创建 OpenCV 图像(160x128RGB888
Mat image(128, 160, CV_8UC3, Scalar(0, 0, 0));
while (true)
{
Mat frame;
cap >> frame; // 从摄像头获取一帧图像
if (frame.empty())
{
cerr << "Error: Cannot grab frame from camera" << endl;
break;
}
// 缩放图像到160x90
Mat resized_frame;
resize(frame, resized_frame, Size(160, 90));
// 转换为灰度图像
Mat gray;
cvtColor(resized_frame, gray, COLOR_BGR2GRAY);
// 使用Haar级联分类器检测人脸
vector<Rect> faces;
face_cascade.detectMultiScale(gray, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
// 在图像上绘制检测到的人脸
for (const auto &face : faces)
{
rectangle(resized_frame, face, Scalar(255, 0, 0), 2);
}
// 将图像居中显示到160x128的framebuffer
image.setTo(Scalar(0, 0, 0)); // 清空图像
int y_offset = (128 - 90) / 2;
resized_frame.copyTo(image(Rect(0, y_offset, 160, 90)));
// 将 OpenCV 图像(RGB888)转换为 RGB565 并写入 Framebuffer
for (int y = 0; y < image.rows; y++)
{
for (int x = 0; x < image.cols; x++)
{
Vec3b color = image.at<Vec3b>(y, x);
fb_data[y * vinfo.xres + x] = rgb888_to_rgb565(color);
}
}
// 等待一段时间
usleep(33333);
}
// 释放资源
munmap(fb_data, fb_size);
close(fb_fd);
cap.release();
return 0;
}