上位机图像处理和嵌入式模块部署(极致成本下的图像处理)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        目前,大家都习惯了特定的图像处理方式,要么是windows上位机来处理,要么是arm soc来进行处理,要么是fpga或者是nvidia gpu来对图像进行处理。但是,这几种方法都有一个共同的特点,那就是对处理器的性能要求高。大家有没有想过,假设运算资源不是很充足,获取的图像分辨率不是很高,在这种情况下还要对图像处理的话,或者是完成特定的一个功能,我们是不是就要想想别的办法了。这样的话,soc是不可能了,mcu也许比较合适一点。此外,opencv库也不好使了,算法也需要我们自己用c写出来。

        为了说明这种情况下,图像应该怎么处理,我们不妨借助于qt来仿真一下整个流程。

1、创建一个基于widget的qt工程

        首先创建一个qt工程,主要是替我们完成图像的解析和保存。

2、借助于qt实现图像的加载和保存

        这里创建qt的目的,主要还是为了演示一下怎么用qt来打开图像和保存图像。实际在嵌入式模块执行的时候,一般我们可以直接拿到图像裸数据的,也不存在文件解析的地方。

#include <QImage>
#include <QDebug>
#include <malloc.h>
#include <assert.h>// generate binary image here
static unsigned char* p_mem = NULL;
void generate_binary_img(unsigned char* p_char, int width, int height);void processImage(QString inputPath, QString outputPath)
{// load imageQImage inputImage(inputPath);if (inputImage.isNull()){qDebug() << "Failed to load image";return;}// get image infoint width = inputImage.width();int height = inputImage.height();p_mem = (unsigned char*)malloc(width * height);assert(p_mem);// loop to process pixelunsigned char* p_data = p_mem;for (int y = 0; y < height; ++y){for (int x = 0; x < width; ++x){QRgb pixel = inputImage.pixel(x, y);// get dataint red = qRed(pixel);int green = qGreen(pixel);int blue = qBlue(pixel);// get grayint gray = qGray(red, green, blue);// save gray to matrix memory*p_data= gray;p_data++;}}// process binary heregenerate_binary_img(p_mem, width, height);// loop to save pixelfor (int y = 0; y < height; ++y){for (int x = 0; x < width; ++x){// set grayunsigned char gray = p_mem[y * width + x];inputImage.setPixel(x, y, qRgb(gray, gray, gray));}}// save dataif (!inputImage.save(outputPath)){qDebug() << "Failed to save processed image";}// free data hereif(p_mem) free(p_mem);
}

        代码当中有两个地方需要注意一下,第一个地方,它生成了gray灰度值,并且把这个数值保存到了p_mem指向的空间里面。第二个地方,它把来自于p_mem的数据,保存到inputImage的下面。这两个部分中间的generate_binary_image函数,才是我们需要真正处理的地方。

3、编写纯图像算法

        纯图像算法,一般就是对内存数据进行操作和处理。操作的方法,通常就是数字图像处理和分析的基本方法。编写的过程中,尽量参照算法的基本逻辑来。同时,参考一下效率,

void generate_binary_img(unsigned char* p_char, int width, int height)
{unsigned char* p_outer;unsigned char* p_inner;int x, y;for (y = 0, p_outer = p_char; y < height; ++y, p_outer += width){p_inner = p_outer;for (x = 0; x < width; ++x, ++p_inner){if (*p_inner > 120)*p_inner = 255;else*p_inner = 0;}}
}

4、文件整合和处理

        所有的内容都准备好之后,就可以加入main函数,实现代码的测试了。这部分内容比较简单,大家直接看代码就好了。目前整个过程都是在windows平台完成的,主要还是因为windows上面开发和调试比较方便。

int main()
{// set input and output pathQString inputPath = "D:/lena.bmp";QString outputPath = "D:/lena_binary.bmp";// process imageprocessImage(inputPath, outputPath);return 0;
}

5、从soc到mcu

        和soc相比较,mcu的算力、内存和flash都是不足的,所以一般为了处理图像,会找一些频率高一点的mcu,比如400m的h7。内存方面,mcu通常只有1m左右,这部分未必能够满足需要,通常会外扩一个sram chip。flash的话,通常不做要求,如果要数据导出的话,裸数据存到micro sd卡即开。保存的方式,可以直接是二进制保存,没必要保存成为bmp格式,到时候自己写一个解析的上位机即可。

6、软件编写

        因为mcu的库比较少,语法支持上面也比较有限,所以大家编写算法的时候尽可能简单明了,不要用太多的语法糖。如果是为了提高效率,尽量使用空间换时间的方法来解决。另外,mcu虽然性能差一点,但是胜在稳定性和成本方面,作为产品开发来说,也是很好的一个选择,大家不必过多地去矮化mcu。只要能满足需求,降低成本,就是好的方案、优秀的方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/649055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

亚信安慧AntDB:赋能业务核心 助力数据管理

在当今数据驱动的信息时代&#xff0c;数据库面临着前所未有的挑战与机遇。随着技术的不断进步和用户需求的多样化&#xff0c;传统的数据库解决方案已经难以满足运营商核心业务的复杂需求。亚信安慧AntDB数据库&#xff0c;作为一款强大数据库产品&#xff0c;旨在帮助运营商应…

JavaScript基础之基本数据类型(值类型)详解

数据类型 数据类型是指可以在程序中存储和操作的值的类型&#xff0c;每种编程语言都有其支持的数据类型&#xff0c;不同的数据类型用来存储不同的数据&#xff0c;例如文本&#xff0c;数字等 JavaScript是一种弱类型语言&#xff0c;在定义变量时不需要提前指定变量的类型…

[SwiftUI]Text对字符串中部分字符改变颜色和字体

如图&#xff0c;需要对字符串中部分字符改变颜色和字体。 在 SwiftUI 中合并带有不同样式的文本&#xff0c;应该使用不同的 Text 实例并将它们合并起来。将实例使用 运算符合并起来&#xff0c;每个 Text 实例都保持其自己的样式设置。这种方式可以正常编译并运行&#xff0…

蓝桥杯——每日一练(简单题)

题目 有n个整数&#xff0c;使前面各数顺序向后移m个位置&#xff0c;最后m个数变成前面m个数。写一函数&#xff1a;实现以上功能&#xff0c;在主函数中输入n个数和输出调整后的n个数。 解析 一、list&#xff08;&#xff09;函数配合map&#xff08;&#xff09;函数获得…

DNS是什么?DNS在网络通信中的作用是什么?(国科云)

我们在日常工作生活中&#xff0c;大多数情况是通过域名去访问网站、发送邮件。当我们打开一个域名或者访问一个网页时&#xff0c;我们的计算机需要知道这个网站的IP地址&#xff0c;才能完成数据的收发通信。这时&#xff0c;DNS就发挥了至关重要的作用&#xff0c;它像一个巨…

跨域请求详解

跨域请求 一 同源策略 同源策略&#xff08;Same origin policy&#xff09;是一种约定&#xff0c;它是浏览器最核心也最基本的安全功能&#xff0c;如果缺少了同源策略&#xff0c;则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的&#xff0c;浏…

ps---1.使用置入嵌入的智能化对象命令制作拼贴画

ps—使用置入嵌入的智能化对象命令制作拼贴画 素材 步骤 打开背景图 置入嵌入对象&#xff08;置入完&#xff0c;移动到正确的位置&#xff0c;回车或双击&#xff09; 栅格化图层 重复上述步骤制作拼贴画

第二百八十八回

文章目录 1. 概念介绍2. 使用方法2.1 实现步骤2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取文件类型"相关的内容&#xff0c;本章回中将介绍如何播放视频.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 播放视频是我们常用…

BGP故障分析——邻居无法建立的原因

点赞关注&#xff0c;持续更新&#xff01;&#xff01;&#xff01; BGP邻居关系无法建立的原因 底层IGP网络不通&#xff1b;接口是否调用了ACL过滤了TCP的179端口&#xff1b;邻居的Router ID冲突&#xff1b;配置的邻居的AS号错误&#xff1b;用Loopback建立邻居时没有配…

apex如何保存多行字符串

虽然可以用换行符把很长的字符串放在一行&#xff0c;但是不便于阅读。apex没有像python中三个引号这种直接支持多行字符串的格式&#xff0c;可以用下面这种方法&#xff1a; String query SELECT Project__c, Project__r.Testing_Submitted__c, Project__r.Project_Sub_P…

go语言(二十)---- 有缓冲的channel

有缓冲的channel 举个例子 package mainimport ("fmt""time" )func main() {c : make(chan int,3) //带有缓冲的 channelfmt.Println("len(c) ",len(c),",cap(c)",cap(c))go func() {defer fmt.Println("子go程结束")for i…

视频监控方案设计:EasyCVR视频智能监管系统方案技术特点与应用

随着科技的发展&#xff0c;视频监控平台在各个领域的应用越来越广泛。然而&#xff0c;当前的视频监控平台仍存在一些问题&#xff0c;如视频质量不高、监控范围有限、智能化程度不够等。这些问题不仅影响了监控效果&#xff0c;也制约了视频监控平台的发展。 为了解决这些问…

HTML-框架标签、实体、全局属性和元信息

HTML 1.框架标签 <iframe name"b站" src"https://www.bilibili.com" width"500" height"300" frameborder"0"></iframe>iframe 标签的实际应用&#xff1a; 在网页中嵌入广告。与超链接或表单的 target 配合&a…

Google的guava缓存学习使用

导入依赖 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version> </dependency>使用 项目中使用到了缓存&#xff0c;定义一个切面&#xff0c;拦截类或方法上存在Sy…

SQL 系列教程(六)

目录 SQL FOREIGN KEY 约束 SQL FOREIGN KEY 约束 创建表时的 FOREIGN KEY 约束 修改表时的 FOREIGN KEY 约束 撤销 FOREIGN KEY 约束 SQL CHECK 约束 SQL CHECK 约束 创建表时的 CHECK 约束 修改表的 CHECK 约束 撤销 CHECK 约束 SQL DEFAULT 约束 SQL DEFAULT 约…

[二叉树专题]二叉树最大高度|n叉树最大高度

一、二叉树最大高度 class Solution { public:int maxDepth(TreeNode* root) {if(rootnullptr)return 0;int left maxDepth(root->left)1;int rightmaxDepth(root->right)1;return left>right?left:right;} }; 二、n叉树最大高度 class Solution { public:int maxDe…

QSqlQuery 执行Update 判断执行成功与否

1.执行更新操作的SQL语句 update s_info set name"009" where contact_number "13511112222" 怎么样判断是否确实更新操作是执行成功的 &#xff0c;可以通过下列语句判断 query.numRowsAffected() > 0 2.主要的几步操作如下: QSqlQuery query;query.…

力扣hot100 实现Trie(前缀树) 字典树 一题双解

Problem: 208. 实现 Trie (前缀树) 文章目录 思路复杂度&#x1f49d; TrieNode版&#x1f49d; 二维数组版 思路 &#x1f469;‍&#x1f3eb; 宫水三叶 复杂度 &#x1f49d; TrieNode版 public class Trie {class TrieNode{boolean end;//标记是否有以当前节点为结尾的字…

【Origin绘图系列第4棒】桑基图

Origin绘制桑基图 桑基图&#xff08;Sankey diagram&#xff09;&#xff0c;即桑基能量分流图&#xff0c;也叫桑基能量平衡图。它是一种特定类型的流程图&#xff0c;右图中延伸的分支的宽度对应数据流量的大小&#xff0c;通常应用于能源、材料成分、金融等数据的可视化分…

Linux生成SSH公钥和密钥

目录 前言生成ssh keys使用公钥 前言 SSH&#xff08;Secure Shell&#xff09;是一种网络协议&#xff0c;用于在不安全的网络上安全地进行远程访问和数据传输。它为用户提供了一种加密的通信方式&#xff0c;可以在客户端和服务器之间建立安全的连接。 SSH使用公钥加密技术…