在本文中,我将对使用max78000进行开发做中期总结。由于本人还是机器学习的入门,因此进度较慢,选题方面还没有确定。现在主要介绍包括羽毛板驱动TFT屏幕,以及模型训练。
1.驱动2.4寸TFT显示屏
1)硬件
该显示屏是2.4寸液晶显示屏模块,分辨率240*320。采用4线SPI通讯,内置的驱动芯片是ILI9341。
使用MAX78000的SPI接口连接TFT屏幕的dc、ds、mosi、miso、sck、reset引脚,同时还要给TFT模块的LED引脚提供3.3V的电源,以驱动显示屏的背光。具体的原理图如下:
原理图
将原理图转换成PCB并进行布线
制作PCB。制作PCB主要是考虑到TFT与MAX78000羽毛板的接线比较多,如果纯用杜邦线连接,会存在断连和接触不良的情况。制作的PCB只有75*80mm的大小,这对于调试与放置都有极大的便捷,调试时候只需用USB与电脑连接即可。
2)软件
- 初始化
//时钟初始化
MXC_SYS_Clock_Select(MXC_SYS_CLOCK_IPO);// Switch to 100 MHz clock
SystemCoreClockUpdate();
MXC_Delay(SEC(2)); // Let debugger interrupt if needed
//相机初始化
MXC_DMA_Init();// 为摄像机接口初始化DMA
dma_channel = MXC_DMA_AcquireChannel();
camera_init(CAMERA_FREQ); //相机初始化
ret = camera_setup(IMG_SIZE_X, IMG_SIZE_Y, PIXFORMAT_RGB888, FIFO_THREE_BYTE, USE_DMA, dma_channel);//相机设置
if (ret != STATUS_OK) {
printf("Error returned from setting up camera. Error %d\n", ret);
return -1;
}
//TFT初始化
MXC_TFT_Init(MXC_SPI0, 1, NULL, NULL);
MXC_TFT_SetRotation(ROTATE_270);
MXC_TFT_SetForeGroundColor(WHITE); // set chars to white
MXC_TFT_ClearScreen();
MXC_TFT_SetBackGroundColor(GREEN);
- 屏幕显示字符串函数
void TFT_Print(int x, int y, char *str, int length)//TFT打印字符串 提供字符串、坐标、长度
{
int font = (int)&Arial12x12[0];
text_t text;
text.data = str;
text.len = length;
MXC_TFT_PrintFont(x, y, font, &text, NULL);
}
- 采集一帧图片并在TFT上显示
void load_input(void) //摄像头采集图像并显示
{
uint8_t *frame_buffer;
uint8_t *buffer;
uint32_t imgLen;
uint32_t w, h, x, y;
uint8_t r, g, b;
uint32_t color;
char buff1[TFT_BUFF_SIZE];//字符串
uint8_t image[IMG_SIZE_X * TFT_SCALE][IMG_SIZE_Y * TFT_SCALE][2]; //定义图像数据
camera_start_capture_image(); //捕捉图像
while (!camera_is_image_rcv()) {} //判断图像采集是否成功
camera_get_image(&frame_buffer, &imgLen, &w, &h); //获取一帧缓冲区的图像数据、长度、宽和高
buffer = frame_buffer;
TFT_Print1(5, 210, buff1, snprintf(buff1, sizeof(buff1), "h:%d, w:%d\n,imgLen:%d",h,w,imgLen));//snprintf的返回值是字符串的长度
for (y = 0; y < h; y++) { //像素转换
for (x = 0; x < w; x++) {
r = *buffer++;
g = *buffer++;
b = *buffer++;
buffer++; // skip msb=0x00
// display on TFT
// Convert to RGB565
color = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3);
for (uint8_t i = 0; i < TFT_SCALE; i++) {
for (uint8_t j = 0; j < TFT_SCALE; j++) {
image[x*TFT_SCALE+i][y*TFT_SCALE+j][0] = color >> 8;
image[x*TFT_SCALE+i][y*TFT_SCALE+j][1] = color & 0xff;
}
}
}
}
MXC_TFT_ShowImageCameraRGB565(TFT_OFFSET_X, TFT_OFFSET_Y, (uint8_t *)image, IMG_SIZE_X * TFT_SCALE, IMG_SIZE_Y * TFT_SCALE);
}
3) 显示效果
可以看到可以成功驱动屏幕,并且能将摄像头采集的图像显示在TFT上(上图中TFT显示的画面是视频)。
2.模型训练
由于我对机器学习处于入门阶段,因此我针对性的学习了pytorch。使用已经有的CIFAR10数据集,搭建卷积神经网络进行GPU的训练。CIFAR10是30*30的10类别数据集,分别是
0: "airplane",
1: "automobile",
2: "bird",
3: "cat",
4: "deer",
5: "dog",
6: "frog",
7: "horse",
8: "ship",
9: "truck"
1)模型搭建
搭建一个3层神经网络。
# 创建网络模型
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, 2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(64*4*4, 64),
nn.Linear(64, 10)
)
def forward(self, x):
x = self.model(x)
return x
2)模型训练
# 训练步骤开始
tudui.train()
for data in train_dataloader:
imgs, targets = data
if torch.cuda.is_available():
imgs = imgs.cuda()
targets = targets.cuda()
outputs = tudui(imgs)
loss = loss_fn(outputs, targets)
# 优化器优化模型
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step = total_train_step + 1
if total_train_step % 100 == 0:
end_time = time.time()
print(end_time - start_time)
start_time = time.time()
print("训练次数:{}, Loss: {}".format(total_train_step, loss.item()))
writer.add_scalar("train_loss", loss.item(), total_train_step)
3)使用opencv采集图像识别
在下面的代码中,采用opencv读取摄像头的图像,并且使用训练好的模型进行识别。
import torch
import torchvision
import cv2
from torch import nn
#transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)),
# torchvision.transforms.ToTensor()]) #转换格式32*32的tensor
# 定义一个字典,将索引映射到类别标签
class_mapping = {
0: "airplane",
1: "automobile",
2: "bird",
3: "cat",
4: "deer",
5: "dog",
6: "frog",
7: "horse",
8: "ship",
9: "truck"
}
# 打开摄像头
cap = cv2.VideoCapture(0) # 0表示默认摄像头
# 检查摄像头是否成功打开
if not cap.isOpened():
print("无法打开摄像头")
exit()
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, 2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(64*4*4, 64),
nn.Linear(64, 10)
)
def forward(self, x):
x = self.model(x)
return x
# 加载模型
model = torch.load("tudui_99.pth", map_location=torch.device('cpu'))
model.eval()
while True:
# 逐帧捕获图像
ret, frame = cap.read()
if not ret:
print("无法获取图像帧")
break
# 缩放图像至 [32, 32]
image = cv2.resize(frame, (32, 32))
# 将图像从 BGR 格式转换为 RGB 格式
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 使用 torchvision.transforms.ToTensor() 转换为 PyTorch 张量
transform = torchvision.transforms.ToTensor()
image_tensor = transform(image)
# 添加批量维度 [1, 3, 32, 32]
image = torch.reshape(image_tensor, (1, 3, 32, 32)) # [1,3,32,32]
# 进行推理
with torch.no_grad():
output = model(image)
# 获取分类结果
predicted_class = output.argmax(1).item()
class_label = class_mapping.get(predicted_class)
print("预测类别: {}, 是: {}".format(predicted_class, class_label))
# 在图像上显示结果(可选)
cv2.putText(frame, "Predicted Class: {}, is: {}".format(predicted_class, class_label), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imshow('Camera', frame)
# 按'q'键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头资源
cap.release()
# 关闭所有窗口
cv2.destroyAllWindows()
4)识别效果
可以看到,在识别的10个项目中,可以准确识别出图像里的内容。
3.未来计划
在接下来,根据选题的要求,搭建对应的图像处理的模型,同时搜集相应的数据集,训练好模型。接着就是将模型转换成MAX78000能执行的代码写入到单片机中。如果有其他硬件的加入,还设计对应的电路和PCB。并且完善项目的整体设计。