单片机拍照_将采集的RGB图像封装为BMP格式保存到SD卡

news2024/11/26 5:39:53

文章目录

  • 一、前言
  • 二、BMP文件结构
    • 2.1 BMP图片的格式
      • 说明
    • 2.2 RGB888与RGB565格式是什么?
      • (1)RGB565
      • (2)RGB888
      • (3)区别
      • (4)如何构成
      • (5)示例
  • 三、实现代码
    • 3.1 RGB565转RGB888的代码
    • 3.2 BMP图片封装: 头文件
    • 3.3 BMP图片封装: 源文件

一、前言

BMP (Bitmap) 图像格式是一种无损压缩的位图文件格式,最初由微软公司在Windows操作系统中引入,用于存储图像数据。BMP格式的主要优点是它简单易用,且支持多种颜色深度。这种格式不包含任何压缩算法,这意味着图像的质量不会因为保存而损失,但这也导致了文件大小相对较大。

当前做的项目是采用STM32F103ZET6单片机接上OV7725(带FIFO)摄像头实现图像采集,拍照功能。 OV7725摄像头输出的格式是RGB565像素格式,为了方便将OV7725摄像头返回的图像数据放在SD卡里存储,并且能够在电脑上打开,通过图片查看软件查看。就需要将RGB565像素数据封装成一张图片格式,也就是相当于加一个壳子。这样电脑上的图片查看器就可以正常查看图片了。

目前的图片格式有很多,平时最常见的有JPG、PNG、BMP这些格式。 这里面的JPG是压缩格式,保存的图片可以很小,JPEG使用离散余弦变换(DCT)压缩,这个算法在单片机上实现的要求毕竟高,毕竟单片机的性能摆在这里。 而BMP是不包含任何压缩算法,存储的是原始的像素格式,作为单片机里拍照存储这是首选的图片封装格式了。

image-20240808143807914

image-20240808155917352

image-20240808155931733

整个项目设计完的核心功能是:

通过OV7725摄像头采集一帧RGB565格式的图像,并将其封装成BMP格式后,利用FATFS文件系统存储到SD卡上。项目中,STM32单片机通过SPI协议与SD卡进行通信。由于OV7725摄像头输出的是RGB565格式的数据,而标准BMP文件使用RGB888格式存储像素数据,因此还涉及到了图像格式的转换问题。

要完成这个项目涉及的技术其实也有几个的:

(1)SD卡的驱动编写,SD卡支持SDIO和SPI两种协议。 要说简单那自然首选SPI协议,不过就是速度稍微慢一点。

(2)OV7725摄像头的驱动编写,毕竟要从摄像头里读取数据。分为控制协议和数据总线。

(3)FATFS文件系统的移植,如果在单片机上要以文件的形式管理SD卡,那肯定是需要文件系统了。

(4)BMP图片的格式理解,要将图片保存为BMP图片格式。需要完全理解BMP图片格式的是如何的封装的。

这篇文章最重要的是内容是讲解“ BMP图片如何封装,学习BMP图像格式封装,RGB565与RGB888像素点转换。

二、BMP文件结构

2.1 BMP图片的格式

BMP 文件的内部格式组成:

(1)文件头 (File Header)

  • 类型标识 (bfType): 两个字节,通常为 BM (0x424D),表明文件类型为BMP。
  • 文件大小 (bfSize): 四个字节,表示整个文件的大小(包括文件头、信息头和像素数据)。
  • 保留字段 (bfReserved1, bfReserved2): 通常是0。
  • 数据偏移量 (bfOffBits): 四个字节,指明像素数据相对于文件起始位置的偏移量。

(2)信息头 (Info Header)

  • 头大小 (biSize): 四个字节,信息头的大小。
  • 宽度 (biWidth): 四个字节,图像的宽度(以像素为单位)。
  • 高度 (biHeight): 四个字节,图像的高度(以像素为单位)。高度值可以是正数也可以是负数;正数表示从左下角开始绘制,负数则表示从左上角开始绘制。
  • 平面数 (biPlanes): 通常是1。
  • 位数 (biBitCount): 每个像素的位数,常见的值有1、4、8、16、24或32。
  • 压缩方法 (biCompression): 指定使用的压缩方法,如果是0,则表示没有压缩。
  • 图像大小 (biSizeImage): 压缩后的图像大小,如果未压缩,则该值可能为0。
  • 水平分辨率 (biXPelsPerMeter): 水平方向上的分辨率(每米像素数)。
  • 垂直分辨率 (biYPelsPerMeter): 垂直方向上的分辨率(每米像素数)。
  • 调色板数目 (biClrUsed): 调色板中的颜色数目,如果为0,则表示所有可能的颜色都被使用。
  • 重要颜色数目 (biClrImportant): 重要的颜色数目,如果为0,则表示所有颜色都同样重要。

(3)颜色表 (Color Table)

  • 如果位数小于24,则存在一个颜色表,其中定义了每个像素值所对应的RGB颜色。

(4)像素数据 (Pixel Data)

  • 图像的实际像素数据按照从左到右、从下到上的顺序排列。为了保证每一行的字节数为4的倍数,通常会在每行末尾添加填充字节。

下面是BMP文件格式的一个详细描述,包括每个字段的名称、长度、含义以及它们在文件中的位置。

字段名称类型长度 (字节)描述
bfType字符串2文件类型的标识,通常为 BM (0x424D)
bfSizeDWORD4整个文件的大小,包括文件头、信息头和像素数据
bfReserved1WORD2保留字段,应设为0
bfReserved2WORD2保留字段,应设为0
bfOffBitsDWORD4像素数据相对于文件起始位置的偏移量
biSizeDWORD4信息头的大小,通常为40 (0x28)
biWidthLONG4图像的宽度(以像素为单位),可以是正数或负数
biHeightLONG4图像的高度(以像素为单位),可以是正数或负数
biPlanesWORD2平面数,通常为1
biBitCountWORD2每个像素的位数,常见的值有1、4、8、16、24或32
biCompressionDWORD4压缩方法,如果是0,则表示没有压缩
biSizeImageDWORD4压缩后的图像大小,如果未压缩,则该值可能为0
biXPelsPerMeterLONG4水平方向上的分辨率(每米像素数),通常为0
biYPelsPerMeterLONG4垂直方向上的分辨率(每米像素数),通常为0
biClrUsedDWORD4调色板中的颜色数目,如果为0,则表示所有可能的颜色都被使用
biClrImportantDWORD4重要的颜色数目,如果为0,则表示所有颜色都同样重要
Color TableRGBQUAD0 or more调色板(仅当位数小于24时存在),每个颜色占用4字节
Pixel DataBYTE[]变长像素数据,按从左到右、从下到上的顺序排列,每行可能有填充字节

说明

  • 文件头 (File Header): 从文件的开头到 bfOffBits 字段结束。
  • 信息头 (Info Header): 从 biSize 字段开始,直到 biClrImportant 字段结束。
  • 颜色表 (Color Table): 如果位数小于24,则存在一个颜色表,用于定义每个像素值所对应的RGB颜色。
  • 像素数据 (Pixel Data): 图像的实际像素数据按照从左到右、从下到上的顺序排列。为了保证每一行的字节数为4的倍数,会在每行末尾添加填充字节。

对于24位的BMP文件(即 biBitCount 的值为24),不会存在颜色表,每个像素直接由三个字节(RGB888格式)表示。

2.2 RGB888与RGB565格式是什么?

RGB565和RGB888都是色彩模型在计算机图形学中的具体实现方式,它们分别代表了不同位深的颜色编码方式。这两种格式主要用于存储图像数据,特别是在显示设备和图像处理软件中。

(1)RGB565

RGB565 是一种16位的彩色图像格式,其中红色和蓝色各占用5位,绿色占用6位。这是因为人眼对绿色更为敏感,因此给绿色分配更多的位数来提高颜色精度。这种格式通常用于节省存储空间或减少内存带宽的需求,尤其是在早期的移动设备和嵌入式系统中非常常见。

  • 位分配:
    • 11-15位: 5位红色 ®
    • 5-10位: 6位绿色 (G)
    • 0-4位: 5位蓝色 (B)

这种格式的总位数为16位,可以表示 (2^{16}) 或者 65,536 种不同的颜色。

(2)RGB888

RGB888 是一种24位的彩色图像格式,每种颜色(红、绿、蓝)都使用8位来表示。这意味着每种颜色都有256级灰度等级,总共可以表示 (2^{24}) 或者 16,777,216 种不同的颜色。

  • 位分配:
    • 16-23位: 8位红色 ®
    • 8-15位: 8位绿色 (G)
    • 0-7位: 8位蓝色 (B)

由于RGB888格式使用更多的位数来表示颜色,所以它能够提供更丰富的色彩细节,这对于高保真度的图像来说是非常重要的。

(3)区别

  1. 位深:

    • RGB565: 使用16位,每像素5:6:5的位分配。
    • RGB888: 使用24位,每像素8:8:8的位分配。
  2. 颜色范围:

    • RGB565: 可以表示大约65,536种颜色。
    • RGB888: 可以表示大约16,777,216种颜色。
  3. 用途:

    • RGB565: 更适合于需要节省存储空间的应用,如旧式的显示器、手机屏幕等。
    • RGB888: 适用于需要高色彩保真的应用,如专业摄影、图形设计等领域。
  4. 性能:

    • RGB565: 在存储和传输方面更加高效,但是颜色精度较低。
    • RGB888: 颜色精度更高,但需要更多的存储空间和传输带宽。

(4)如何构成

  • RGB565:

    • 每个像素由两个字节组成。
    • 例如,一个红色像素可能表示为 0xF800(红色部分接近最大值,绿色和蓝色部分接近最小值)。
  • RGB888:

    • 每个像素由三个字节组成。
    • 例如,一个红色像素可能表示为 0xFF0000(红色部分为最大值255,绿色和蓝色部分为0)。

(5)示例

可以创建一个简单的例子来说明这些格式是如何工作的。假设有一个像素,它的红色、绿色和蓝色分量分别为128(十六进制为0x80)。

  • RGB565: 对于每个颜色通道,需要将8位的值转换为相应的位数。

    • 红色: 0x80 -> 0x1F (5位)
    • 绿色: 0x80 -> 0x20 (6位)
    • 蓝色: 0x80 -> 0x1F (5位)

    所以,一个灰色像素在RGB565格式下的值可能是 0x1F201F

  • RGB888: 我们直接使用8位值。

    • 红色: 0x80
    • 绿色: 0x80
    • 蓝色: 0x80

    这样,一个灰色像素在RGB888格式下的值将是 0x808080

三、实现代码

3.1 RGB565转RGB888的代码

下面是一个将 RGB565 数组转换为 RGB888 数组的 C 语言函数:

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

// 将 RGB565 转换为 RGB888 的函数
void RGB565_to_RGB888_array(const uint16_t *rgb565_array, size_t length, uint8_t *rgb888_array) {
    for (size_t i = 0; i < length; i++) {
        uint16_t rgb565 = rgb565_array[i];

        // 提取 RGB565 中的颜色分量
        uint8_t red = (rgb565 >> 11) & 0x1F;  // 5 bits
        uint8_t green = (rgb565 >> 5) & 0x3F; // 6 bits
        uint8_t blue = rgb565 & 0x1F;         // 5 bits

        // 将颜色分量扩展到 8 位
        uint8_t r = (red << 3) | (red >> 2);     // 5 bits to 8 bits
        uint8_t g = (green << 2) | (green >> 4); // 6 bits to 8 bits
        uint8_t b = (blue << 3) | (blue >> 2);   // 5 bits to 8 bits

        // 将结果存储到 RGB888 数组
        rgb888_array[i * 3] = r;
        rgb888_array[i * 3 + 1] = g;
        rgb888_array[i * 3 + 2] = b;
    }
}

int main() {
    // 示例 RGB565 数组
    uint16_t rgb565_array[] = {0x1F3F, 0x07E0, 0xF800};
    size_t length = sizeof(rgb565_array) / sizeof(rgb565_array[0]);

    // 分配 RGB888 数组内存
    uint8_t *rgb888_array = (uint8_t *)malloc(length * 3 * sizeof(uint8_t));
    if (rgb888_array == NULL) {
        perror("Unable to allocate memory for RGB888 array");
        return 1;
    }

    // 转换 RGB565 数组到 RGB888 数组
    RGB565_to_RGB888_array(rgb565_array, length, rgb888_array);

    // 打印 RGB888 结果
    for (size_t i = 0; i < length; i++) {
        printf("RGB888[%zu]: R=%d, G=%d, B=%d\n", i, rgb888_array[i * 3], rgb888_array[i * 3 + 1], rgb888_array[i * 3 + 2]);
    }

    // 释放分配的内存
    free(rgb888_array);

    return 0;
}

这个函数 RGB565_to_RGB888_array 接收一个 RGB565 数组和数组的长度,并返回一个 RGB888 数组。每个 RGB565 值被转换为三个 8 位的 RGB 分量,并存储在提供的 RGB888 数组中。示例中的 main 函数展示了如何调用这个转换函数并打印结果。

3.2 BMP图片封装: 头文件

#ifndef BMP_H
#define BMP_H
#include "ff.h"
#include "string.h"
#include "sys.h"
#pragma pack(1)    /* 必须在结构体定义之前使用,这是为了让结构体中各成员按1字节对齐 */

/*需要文件信息头:14个字节 */
typedef struct tagBITMAPFILEHEADER
{
	unsigned short bfType;      //保存图片类似。 'BM'
	unsigned long  bfSize;      //图片的大小
	unsigned short bfReserved1;
	unsigned short bfReserved2; 
	unsigned long  bfOffBits;  //RGB数据偏移地址
}BITMAPFILEHEADER;

/* 位图信息头 */
typedef struct tagBITMAPINFOHEADER { /* bmih */
	unsigned long  biSize;      //结构体大小
	unsigned long  biWidth;		  //宽度
	unsigned long  biHeight;	  //高度
	unsigned short biPlanes;
	unsigned short biBitCount;	//颜色位数
	unsigned long  biCompression;
	unsigned long  biSizeImage;
	unsigned long  biXPelsPerMeter;
	unsigned long  biYPelsPerMeter;
	unsigned long  biClrUsed;
	unsigned long  biClrImportant;
}BITMAPINFOHEADER;

#define RGB888_RED      0x00ff0000  
#define RGB888_GREEN    0x0000ff00  
#define RGB888_BLUE     0x000000ff  
 
#define RGB565_RED      0xf800  
#define RGB565_GREEN    0x07e0  
#define RGB565_BLUE     0x001f  

u8 photograph_BMP(u8 *filename,int Width,int Height);
void photograph_open(u8 *filename,int Width,int Height);
void  photograph_write(u16 *buff);
void photograph_close(void);
#endif

3.3 BMP图片封装: 源文件

#include "bmp.h"  
unsigned short RGB888ToRGB565(unsigned int n888Color)  
{  
    unsigned short n565Color = 0;  
  
    // 获取RGB单色,并截取高位  
    unsigned char cRed   = (n888Color & RGB888_RED)   >> 19;  
    unsigned char cGreen = (n888Color & RGB888_GREEN) >> 10;  
    unsigned char cBlue  = (n888Color & RGB888_BLUE)  >> 3;  
  
    // 连接  
    n565Color = (cRed << 11) + (cGreen << 5) + (cBlue << 0);  
    return n565Color;  
}  
  
unsigned int RGB565ToRGB888(unsigned short n565Color)  
{  
    unsigned int n888Color = 0;  
  
    // 获取RGB单色,并填充低位  
    unsigned char cRed   = (n565Color & RGB565_RED)    >> 8;  
    unsigned char cGreen = (n565Color & RGB565_GREEN)  >> 3;  
    unsigned char cBlue  = (n565Color & RGB565_BLUE)   << 3;  
  
    // 连接  
    n888Color = (cRed << 16) + (cGreen << 8) + (cBlue << 0);  
    return n888Color;  
} 


//拍摄BMP的图片
u8 photograph_BMP(u8 *filename,int Width,int Height)
{
		u32 cnt;
		int x,y;
	  u8 res;
	  char *p;
		u16 c16; //16位颜色值
	  u32 c32; //24位颜色值
	
	  BITMAPFILEHEADER BmpHead; //保存图片文件头的信息
	  BITMAPINFOHEADER BmpInfo; //图片参数信息
	
	  /*1. 创建BMP文件*/
		FIL  file;
		res = f_open(&file,(char*)filename, FA_OPEN_ALWAYS | FA_READ | FA_WRITE); //读写加创建
	  if(res!=0)return 1;
	  
	  /*2. 填充图片数据头*/
		memset(&BmpHead,0,sizeof(BITMAPFILEHEADER));
		p=(char*)&BmpHead.bfType; //填充BMP图片的类型
		*p='B';
		*(p+1)='M';
		//BmpHead.bfType=0x4d42;//'B''M'   //0x4d42
		BmpHead.bfSize=Width*Height*3+54; //图片的总大小
		BmpHead.bfOffBits=54;             //图片数据的偏移量
	  res=f_write(&file,&BmpHead,sizeof(BITMAPFILEHEADER),&cnt);//写入图片文件头到文文件
	  if(res!=0)return 1;
	  
	  /*3. 填充图片参数*/
	  memset(&BmpInfo,0,sizeof(BITMAPINFOHEADER));
		BmpInfo.biSize=sizeof(BITMAPINFOHEADER); //当前结构体大小
		BmpInfo.biWidth=Width;
		BmpInfo.biHeight=Height;
		BmpInfo.biPlanes=1;
		BmpInfo.biBitCount=24;
		res=f_write(&file,&BmpInfo,sizeof(BITMAPINFOHEADER),&cnt);//写入图片文件头到文文件
	  if(res!=0)return 1;
		
		/*4. 读取图像参数进行填充*/
		for(y=Height-1;y>=0;y--) //因为BMP图片特性,所有需要从LCD最后一行开始读
		{
			for(x=0;x<Width;x++)
			{
				//c16=LcdReadPoint(x,y);      //LCD读点函数
				c32=RGB565ToRGB888(c16);    //将16位的颜色转为32位
				f_write(&file,&c32,3,&cnt); //写入图片数据
			}
		}
		
		/*. 关闭文件*/
		f_close(&file);
		return 0;
}


BITMAPFILEHEADER BmpHead; //保存图片文件头的信息
BITMAPINFOHEADER BmpInfo; //图片参数信息
#include <stdio.h>
FIL  BMP_file;
//拍摄1: 创建文件
void photograph_open(u8 *filename,int Width,int Height)
{
		u32 cnt;
	  u8 res;
	  char *p;

	  /*1. 创建BMP文件*/
		res = f_open(&BMP_file,(char*)filename, FA_OPEN_ALWAYS | FA_READ | FA_WRITE); //读写加创建
	  if(res!=0)
    {
      printf("%s文件打开失败.!\r\n",filename);
      return;
    }
	  
	  /*2. 填充图片数据头*/
		memset(&BmpHead,0,sizeof(BITMAPFILEHEADER));
		p=(char*)&BmpHead.bfType; //填充BMP图片的类型
		*p='B';
		*(p+1)='M';
		//BmpHead.bfType=0x4d42;//'B''M'   //0x4d42
		BmpHead.bfSize=Width*Height*3+54; //图片的总大小
		BmpHead.bfOffBits=54;             //图片数据的偏移量
	  res=f_write(&BMP_file,&BmpHead,sizeof(BITMAPFILEHEADER),&cnt);//写入图片文件头到文文件
	  if(res!=0)
    {
       printf("%s BMP文件头1写入失败.!\r\n",filename);
       return;
    }
    else
    {
         printf("%s BMP文件头1写入成功!.%d字节.\r\n",filename,cnt);
    }
	  
	  /*3. 填充图片参数*/
	    memset(&BmpInfo,0,sizeof(BITMAPINFOHEADER));
		BmpInfo.biSize=sizeof(BITMAPINFOHEADER); //当前结构体大小
		BmpInfo.biWidth=Width;
		BmpInfo.biHeight=Height;
		BmpInfo.biPlanes=1;
		BmpInfo.biBitCount=24;
		res=f_write(&BMP_file,&BmpInfo,sizeof(BITMAPINFOHEADER),&cnt);//写入图片文件头到文文件
	  if(res!=0)
    {
        printf("%s BMP文件头2数据写入失败.!\r\n",filename);
        return;
    }
    else
    {
         printf("%s BMP文件头2数据写入成功.!%d字节\r\n",filename,cnt);
    }
}


//拍摄2: 写文件
void photograph_write(u16 *buff)
{
    u32 c32; //24位颜色值
    UINT cnt;
    u8 res;
    int x;
    /*4. 读取图像参数进行填充*/
    for(x=0;x<320;x++)
    {
        c32=RGB565ToRGB888(buff[x]);    //将16位的颜色转为32位
        res=f_write(&BMP_file,&c32,3,&cnt); //写入图片数据
        if(res!=0)
        {
            printf("图像数据写入失败.%d\r\n",x);
            break;
        }
    }
}


//拍摄3: 关闭文件
void photograph_close(void)
{
     /*. 关闭文件*/
	f_close(&BMP_file);
}

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

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

相关文章

yolo训练出现Could not load library libcudnn_cnn_train.so.8问题及解决方法

问题场景&#xff1a; 训练yolov5或者yolov8时候会报错&#xff1a; Could not load library libcudnn_cnn_train.so.8. Error: /usr/local/cuda-12.1/lib64/libcudnn_cnn_train.so.8: uined symbol: _ZN5cudnn3cnn34layerNormFwd_execute_internal_implERKNS_7backend11Vari…

【EasyExcel】@ColumnWidth(value = 20) EasyExcel设置列宽不生效

经过测试发现&#xff0c;只有XLS&#xff0c;ColumnWidth注解才会生效&#xff0c;选择CSV和XLSX都不会生效 //对应的导出实体类 EasyExcel.write(outputStream, Result.class)//excel文件类型&#xff0c;包括CSV、XLS、XLSX.excelType(ExcelTypeEnum.XLS)

当你学会了Python,随手爬取电影榜单!

一、爬电影TOP250 python爬取电影TOP250数据&#xff01; 首先&#xff0c;打开电影TOP250的页面&#xff1a; https://movie.douban.com/top250 开发好python代码后&#xff0c;成功后的csv数据&#xff0c;如下&#xff1a; 代码是怎样实现的爬取呢&#xff1f;下面逐一讲…

计算机网络相关概念

名词解释&#xff1a; 1.ARPANET ARPANET&#xff08;Advanced Research Projects Agency Network&#xff09;是由美国国防部高级研究计划局&#xff08;ARPA&#xff09;在1969年启动的一个实验性计算机网络项目。它是世界上第一个分组交换网络&#xff0c;也是互联网的前身…

springboot《计算机网络》在线考试系统-计算机毕业设计源码22248

摘要 计算机网络课程是计算机科学与技术、信息技术及相关专业的一门重要课程。然而&#xff0c;在传统的教育模式下&#xff0c;计算机网络课程的考核方式多以纸质试卷为主&#xff0c;这种方式存在诸多弊端。一方面&#xff0c;试卷的编制、印刷、分发、收缴等环节耗时耗力&am…

遗传算法求解VRP路径规划问题

文章目录 题目&#xff1a;快递公司送货策略VRP问题简介遗传算法项目地址代码说明代码结构求解流程举例求解目标求解步骤 总结 打数模国赛前拿来练手的题&#xff0c;现在题目求解思路分享给大家&#xff0c;包括 所有源代码 和 高清pdf论文&#xff0c;希望能对大家有所帮助…

多线程篇(其它容器- CopyOnWriteArrayList)(持续更新迭代)

一、CopyOnWriteArrayList&#xff08;一&#xff09; 1. 简介 并发包中的并发List只有CopyOnWriteArrayList。 CopyOnWriteArrayList是一个线程安全的ArrayList&#xff0c;对其进行的修改操作都是在底层的一个复制的数 组&#xff08;快照&#xff09;上进行的&#xff0…

解决 git 不是内部或外部命令,也不是可运行的程序

目录 报错提示&#xff1a; 一、解决办法 1、从git官网下载windows版本的git 2、安装 3、注意事项 二、报错 1、解决 fatal: Not a git repository (or any of the parent directories): .git 问题 报错提示&#xff1a; 一、解决办法 Windows下配置Git&#xff1a; 1…

sap公司间交易(采购单转储)-公司间交易价格的配置

sap 公司间交易(采购单转储)-公司间交易价格的配置 对于通过采购单转储方式实现公司间交易,公司间交易价系统标准设计是,购货方采用采购单上的单价做为发票校验的价格,而销售方由于没有销售单,则采用的是在 vk11 里维护的公司间售价,这种做法的坏处是经常要同步这两个价格…

error C2275: 将此类型用作表达式非法-解决方案

最近在进行将C移植C的项目&#xff0c;代码改完&#xff0c;生成解决方案时&#xff0c;出现如下错误&#xff1a; 在移植c代码到c的时候&#xff0c;经常会出现一个奇怪的错误&#xff1a;“error C2275: “xxxxx”: 将此类型用作表达式非法” 两个错误属于同一类型&#xff…

投资一家无人机培训机构技术详解

无人机培训机构是随着无人机技术的快速发展和普及而兴起的一种专业培训机构。这类机构专注于为学员提供无人机相关的理论知识、操控技能以及应用技术培训&#xff0c;以满足不同领域对无人机人才的需求。 1. 市场调研与定位 市场调研 在投资无人机培训机构之前&#xff0c;深…

OpenWRT有三个地方设置DNS,究竟设置哪个地方会更好?

前言 刚上手OpenWRT软路由系统的小伙伴或许都会有这样的疑问&#xff1a;OpenWRT这个系统有三个地方是设置DNS的&#xff0c;究竟设置哪一个才是正确的&#xff1f; 这个还得从实际应用说起。 一般来说&#xff0c;咱们在使用路由器的时候&#xff0c;DNS都是默认运营商的DN…

YOLOV3实现越界检测——智能安防

目录 应用前景 1. 安全监控系统 2. 家庭安防系统 3. 无人机监控 4. 交通管理 5. 无人驾驶技术 6. 大型活动现场 代码说明 1. YOLO 模型加载 2. 摄像头视频流捕获 3. 安全区域绘制 4. YOLOv3 目标检测 5. 过滤和标记人类目标 6. 入侵检测 7. 结果显示和退出 总结…

黑神话怎么录?游戏录屏必备,探索2024年7款游戏录屏软件排行榜

在游戏世界中&#xff0c;记录下每一个精彩瞬间已成为玩家们的共同需求。2024年&#xff0c;随着《黑悟空神话》等大作的问世&#xff0c;玩家们对于游戏录屏软件的需求愈发高涨。本文将为您推荐几款在2024年备受好评的游戏录屏软件&#xff0c;帮助您捕捉游戏中的每一个高光时…

NLP-文本分类文献阅读-前置基础-词汇解释-通俗易懂-9月份-学习总结

目录 迁移学习 特征选择 特征工程 朴素贝叶斯分类方法 支持向量机 K-最近邻&#xff08;K-Nearest Neighbors, KNN&#xff09; 特征向量稀疏 卷积神经网络 循环神经网络 图神经网络 TextCNN 动态 K 最大池化 One-hot BOW Word2vec 池化&#xff08;Pooling&#xff09; 全连接…

Python画笔案例-043 绘制“篱笆“

1、绘制 “篱笆” 通过 python 的turtle 库绘制 “篱笆”&#xff0c;如下图&#xff1a; 2、实现代码 绘制 “篱笆”&#xff0c;以下为实现代码&#xff1a; """篱笆.py """ import turtledef draw_triangle():"""画正三角形函…

万物皆AI:联发科技 Genio 130 与 ChatGPT 的火花 - 基于 MTK Genio 130 结合 ChatGPT 功能的解决方案

随着人工智慧(AI)在2022-2023的爆炸性成长&#xff0c;我们迎来了AI世代&#xff0c;无论是交通、工业、金融、制造、医疗等各领域&#xff0c;AI已被广泛的应用来解决各类问题与加速发展。伴随著AI走入我们的生活&#xff0c;我们也在所拥有的各类智慧装置上&#xff0c;看到各…

农田杂草检测数据集 2900张 杂草检测 带标注 voc yolo

这是一个关于农田杂草的图像识别数据集&#xff0c;包含了2900张带标注的图片&#xff0c;可以用于训练计算机视觉算法&#xff0c;如VOC或YOLO等目标检测模型。 该数据集中包含以下10类农田杂草&#xff1a; Carpetweeds&#xff08;450张&#xff09;Crabgrass&#xff08;1…

基于JavaWeb开发的Java+SpringMvc+vue+element实现上海汽车博物馆平台

基于JavaWeb开发的JavaSpringMvcvueelement实现上海汽车博物馆平台 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接…