基于imx6ull平台opencv的图像采集和显示屏LCD显示功能(不带Qt界面)

目录

一、概述

本文档是针对imx6ull平台opencv的图像采集和显示屏LCD显示功能,opencv通过摄像头采集视频图像,将采集的视频图像送给显示屏LCD进行显示。

  • 测试结果如下图所示:

二、环境要求

2.1 硬件环境

  • 硬件:正点原子-I.MX6U ALPHA开发板
  • 摄像头:正点原子-OV5640单目摄像头
  • 显示屏:正点原子-4.3寸-800x480显示屏
  • 虚拟机:VMware

2.2 软件环境

  • Ubuntu系统要求:20.04
  • opencv版本: 4.7.0
  • 交叉工具链版本:交叉工具链版本:gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf
  • 开发语言: C++

注意: 其中,需要有OV5640单目摄像头和4.3寸-800x480显示屏的驱动。

三、开发流程

关于imx6ull平台下opencv的移植及交叉编译器环境请参看:基于imx6ull开发板 移植opencv4.7.0

3.1 编写测试

选择一个目录,我这里选择的是opencv_lcd_imx6ull,创建一个opencv_lcd.cpp文件,内容如下:

cpp 复制代码
#include <opencv2/opencv.hpp>
#include <opencv2/videoio/videoio.hpp>
#include <opencv2/core/utils/logger.hpp>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>

/**** 静态全局变量 ****/
static int width;                       //LCD X分辨率
static int height;                      //LCD Y分辨率
static unsigned short *screen_base = NULL;        //映射后的显存基地址
static unsigned long line_length;       //LCD一行的长度(字节为单位)

using namespace std;
using namespace cv;
 
int main() {
    struct fb_fix_screeninfo fb_fix;
    struct fb_var_screeninfo fb_var;
    unsigned int screen_size;

    // 打开LCD设备
    int fb = open("/dev/fb0", O_RDWR);
    if (fb < 0) {
        perror("open fb0 failed");
        return -1;
    }

    /* 获取参数信息 */
    // 获取LCD屏幕信息
    if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) < 0) {
        perror("ioctl FBIOGET_VSCREENINFO failed");
        return -1;
    }
 
    // 获取LCD帧缓冲区信息
    if (ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix) < 0) {
        perror("ioctl FBIOGET_FSCREENINFO failed");
        return -1;
    }
    // 初始化OpenCV
    cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_SILENT);

    //括号内数字为1是调用usb摄像头,为0则是调用电脑自带摄像头
    cv::VideoCapture capture(1);
    unsigned short *screen_ptr = screen_base;

    // 设置摄像头的分辨率
    cv::Size resolution(800, 480);
    capture.set(cv::CAP_PROP_FRAME_WIDTH, resolution.width);
    capture.set(cv::CAP_PROP_FRAME_HEIGHT, resolution.height);

    // 加载预先训练好的人脸识别模型
    cv::CascadeClassifier faceCascade;
    faceCascade.load("haarcascade_frontalface_default.xml");

    // 将图像数据写入LCD屏幕
    screen_size = fb_fix.line_length * fb_var.yres;
    line_length = fb_fix.line_length;
    width = fb_var.xres;
    height = fb_var.yres;
    screen_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
    if (MAP_FAILED == (void *)screen_base) {
        perror("mmap failed");
        return -1;
    }
    
    memset(screen_base, 0xFF, screen_size);
    unsigned short *fb_line_buf = NULL; //行缓冲区:用于存储写入到LCD显存的一行数据

    cv::Mat image;  //定义一个Mat变量,用于存储每一帧的图像
    capture >> image;  //读取当前帧
    printf("%d %d %d\r\n", image.cols, image.rows, image.channels());
    fb_line_buf = malloc(image.cols * 2);

    //【2】循环显示每一帧
	while(1)  
	{  
		// cv::Mat image;  //定义一个Mat变量,用于存储每一帧的图像
		capture >> image;  //读取当前帧
        // printf("%d %d %d\r\n", image.cols, image.rows, image.channels());
        screen_ptr = screen_base;
        if (image.empty()) continue; // 如果没有读取到帧,退出循环

        for (size_t y = 0; y < image.rows; y++)
        {
            char* row_ptr = image.ptr<char>(y);
            for (size_t x = 0; x < image.cols; ++x) {
                //这是获得像素数据数组的头指针,注意像素数据可能会有多个通道所以才需要用数组存储
                char* data_ptr = &row_ptr[x * image.channels()];
                // //对当前像素逐个通道输出颜色值
                // for (int i = 0; i < image.channels(); ++i) {
                //     cout << int(data_ptr[i])<<endl;
                // }
                // BGR888转为RGB565
                fb_line_buf[x] = ((data_ptr[2] & 0xF8) << 8) |
                    ((data_ptr[1] & 0xFC) << 3) |
                    ((data_ptr[0] & 0xF8) >> 3);
            }
            memcpy(screen_ptr, fb_line_buf, image.cols * 2);//将一行数据刷入显存
            screen_ptr += width;   //定位到显存下一行

        }
        
	}  

    // 解除内存映射
    munmap(screen_base, screen_size);
 
    // 关闭LCD设备
    close(fb);
 
    return 0;
}

opencv_lcd_imx6ull目录下,创建一个build_arm.sh文件,内容如下:

bash 复制代码
/tools/ToolsChain/nxp/imx6ull/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ opencv_lcd.cpp -o opencv_lcd \
-I /data/Workspace_Linux/software_lib/opencv-x.x.x/output/opencv-4.7.0/imx6ull/include/opencv4 \
-L /data/Workspace_Linux/software_lib/opencv-x.x.x/output/opencv-4.7.0/imx6ull/lib \
-lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_videoio -lopencv_imgcodecs -lopencv_face -lopencv_dnn  -lopencv_features2d -lopencv_flann -lopencv_calib3d -lopencv_objdetect \
-fpermissive

注意:

  • 交叉工具链:/tools/ToolsChain/nxp/imx6ull/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++;
  • opencv头文件路径:/data/Workspace_Linux/software_lib/opencv-x.x.x/output/opencv-4.7.0/imx6ull/include/opencv4,开发者根据自己的路径进行配置;
  • opencv库路径:/data/Workspace_Linux/software_lib/opencv-x.x.x/output/opencv-4.7.0/imx6ull/lib,开发者根据自己的路径进行配置。

3.2 验证功能

  • 源码编译并上传
    opencv_lcd_imx6ull目录下,将build_arm.sh文件更改成可执行文件,并运行如下图所示:
bash 复制代码
./build_arm.sh

进入imx6ull开发板的/mnt/test_opencv目录下(若没有改目录则创建该目录),创建opencv_lcd目录,如下图所示:

opencv_lcd文件通过tfp上传到imx6ull开发板的/mnt/test_opencv/opencv_lcd目录下,如下图所示:

  • opencv库上传到imx6ull开发板
    进入/data/Workspace_Linux/software_lib/opencv-x.x.x/output/opencv-4.7.0/imx6ull目录下,将opencv库相关的内容进行打包,如下图所示:

    进入imx6ull开发板的/mnt/test_opencv目录下(若没有改目录则创建该目录),创建opencv目录,如下图所示:

    opencv.tar文件通过tfp上传到imx6ull开发板的/mnt/test_opencv/opencv目录下,如下图所示:

    进入imx6ull开发板的/mnt/test_opencv/opencv目录下,执行以下命令,将opencv.tar文件进行解压,如下图所示:
bash 复制代码
tar -xf opencv.tar
  • opencv库配置环境搭建

执行以下命令进行opencv库环境配置,如下图所示:

bash 复制代码
export LD_LIBRARY_PATH=/mnt/test_opencv/opencv/lib:$LD_LIBRARY_PATH
  • 运行应用程序

进入imx6ull开发板的/mnt/test_opencv/opencv_lcd目录下,更改opencv_lcd为可执行文件,并运行,运行结果如下:

最后,基于imx6ull平台opencv的图像采集和显示屏LCD显示功能验证完成了。

相关推荐
宁渡AI大模型4 小时前
河南宁渡科技有限公司|宁渡课堂 AI 全栈面试分享,RAG 项目面试深挖问题解析
人工智能·机器学习·rag
锋行天下10 小时前
LangGraph 1.2+ 新特性:set_node_defaults,批量统一节点策略
人工智能
找方案10 小时前
AI+人力资源:AI招聘面试的兴起与争议
人工智能·面试·职场和发展
日常通勤穿搭10 小时前
2026 电商 AI 作图工具推荐|淘宝抖音跨境商品主图 AI 生图测评
人工智能·aigc·ai工具·电商美工
ZhengEnCi10 小时前
L2A-一个域名如何访问多台云服务器-子域名、路径前缀与Nginx反向代理选型指南
linux·人工智能
2601_9637491010 小时前
越华环保集团污水站曝气系统边缘闭环控制架构与能耗优化实现
人工智能·架构
工业涂料百问10 小时前
【生产施工】系列(六)工业涂料固化方式怎么选?自然干 / UV / 电子束原理与选型实战
人工智能
葡萄城技术团队11 小时前
活字格 12.1 新特性解密:禁用自动回复后,AI 对话单元格也能流式输出了
人工智能
东风破_11 小时前
从 RAG 到 Agentic RAG:第一步,让模型决定「要不要检索」
人工智能
火山引擎开发者社区11 小时前
一图看懂 ADrive 跨产品协作实践:文件通了,Agent 就通了
人工智能