上一次使用MAX78000开发板读取摄像头后,使用TFT屏幕显示。虽然成功显示在TFT屏幕上了,但是面包板使用起来还是不够方便,屏幕刷新慢,自己也不确定是TFT屏幕慢?还是MAX78000开发板读取摄像头慢?最重要一点是MAX78000开发板读取到的摄像头的图像最终是想实现机器学习的训练的,所以有对图片保存的需要,于是就有想把摄像头读取到的图片上传给电脑,进行保存和展示。

MAX7800FEATHER开发板上集成了很多传感器,但是板子上却没有wifi、蓝牙或是网口等通讯功能,与上位机的通讯只能通过串口来完成。在学习美信官方提供的例程时发现“MaximSDK\Examples\MAX78000\CameraIF\pc_utility”这样一个文件夹,使用python写的一个上位机的例程,python也算略懂,于是开始学习这个例程的上位机部分。
第一步:串口初始化。这个开发板的串口还是挺强劲的,使用了921600波特率,换算下来,每秒大约能传输 92160 字节(约 90 KB/s)。一张图片,使用240*240的分辨率,RGB565方式编码,那么每传递一帧图片需要1.25秒,
速度还是慢啊!
#define CON_BAUD 115200 * 8 // UART baudrate used for sending data to PC, use max 921600 for serial stream
// Initialize DMA for camera interface
MXC_DMA_Init();
dma_channel = MXC_DMA_AcquireChannel();
mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(CONSOLE_UART);
if ((ret = MXC_UART_Init(ConsoleUart, CON_BAUD, MXC_UART_IBRO_CLK))
!= E_NO_ERROR) {
return ret;
}第二步:摄像头初始化。下位机我将例程的代码做了精简。基本流程为 DMA初始化——I2C初始化——摄像头初始化——摄像头启动。这里使用了240X240的分辨率,图像使用RGB565编码。
int main(void) {
int ret = 0;
int slaveAddress;
int id;
int dma_channel;
/* Enable cache */
MXC_ICC_Enable(MXC_ICC0);
/* Set system clock to 100 MHz */
MXC_SYS_Clock_Select(MXC_SYS_CLOCK_IPO);
SystemCoreClockUpdate();
// Initialize DMA for camera interface
MXC_DMA_Init();
dma_channel = MXC_DMA_AcquireChannel();
mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(CONSOLE_UART);
if ((ret = MXC_UART_Init(ConsoleUart, CON_BAUD, MXC_UART_IBRO_CLK))
!= E_NO_ERROR) {
return ret;
}
// Initialize the camera driver.
camera_init(CAMERA_FREQ);
printf("\n\nCamera Example\n");
slaveAddress = camera_get_slave_address();
printf("Camera I2C slave address: %02x\n", slaveAddress);
// Obtain the manufacturer ID of the camera.
ret = camera_get_manufacture_id(&id);
if (ret != STATUS_OK) {
printf("Error returned from reading camera id. Error %d\n", ret);
return -1;
}
printf("Camera ID detected: %04x\n", id);
// Setup the camera image dimensions, pixel format and data acquiring details.
ret = camera_setup(IMAGE_XRES, IMAGE_YRES, PIXFORMAT_RGB565, FIFO_FOUR_BYTE,
STREAMING_DMA, dma_channel); // RGB565 stream
// ret = camera_setup(IMAGE_XRES, IMAGE_YRES, PIXFORMAT_GRAYSCALE, FIFO_FOUR_BYTE, STREAMING_DMA,dma_channel); // �Ҷ�ͼ stream
if (ret != STATUS_OK) {
printf("Error returned from setting up camera. Error %d\n", ret);
return -1;
}
MXC_Delay(SEC(1));
camera_write_reg(0x11, 0xE); // can be set to 0xB in release mode ( -o2 )
// Start capturing a first camera image frame.
printf("Starting\n");
camera_start_capture_image();
while (1) {
{
// Process the image, send it through the UART console.
process_img();
// Prepare for another frame capture.
LED_Toggle(LED_GREEN);
camera_start_capture_image();
}
}
return ret;
}第三步:从DMA读取摄像头采集数据,上送串口。
// 从DMA中读取图片,写入内存
void read_img_fromdma(uint32_t w, uint32_t h, uint8_t *imgdata) {
uint8_t *data = NULL;
// Get image line by line
for (int i = 0; i < h; i++) {
// Wait until camera streaming buffer is full
while ((data = get_camera_stream_buffer()) == NULL) {
if (camera_is_image_rcv()) {
break;
}
}
for (int j = 0; j < w * 2; j++) {
imgdata[i * w * 2 + j] = data[j];
}
// Release stream buffer
release_camera_stream_buffer();
}
}
void process_img(void) {
uint8_t *raw;
uint32_t imgLen;
uint32_t w, h;
// Get the details of the image from the camera driver.
camera_get_image(&raw, &imgLen, &w, &h);
uint8_t *imgdata = (uint8_t*) malloc(imgLen); //使用灰度图 尺寸减半 动态申请内存
utils_stream_img_to_pc_init(raw, imgLen, w, h, camera_get_pixel_format());
read_img_fromdma(w, h, imgdata); //从DMA中读取图片信息,并转换为灰度图,写入imgdata
utils_stream_image_row_to_pc(imgdata, w * h * 2);
free(imgdata);
stream_stat_t *stat = get_camera_stream_statistic();
if (stat->overflow_count > 0) {
LED_On(LED_RED); // Turn on red LED if overflow detected
while (1) {
}
}
}摄像头每次采集到一帧图片后,就将图片数据写到DMA缓存,代码动态申请一段内存,然后将图片信息从DMA区读取到内存里,最后通过串口发送出去。
第四步:上位机。在上位机中手工指定了串口号,波特率选择与下位机相同的921600。其余无改动。上位机的基本思路为:打开串口监听——收到串口数据信息(格式、长度)——接收串口数据——接收完成后保存图片文件——通过OPENCV展示保存了的图片。
comport = "COM5" # # Setup the default baudrate. baudRate = 921600 # 115200
while True:
if ( comManager.find_sync() == 1 ):
print ("\n\n***Sync word found***", flush=True)
print ("Reading image bytes, please wait...", flush=True)
# width
arr = comManager.read(2)
w = arr[0]*256 + arr[1]
# height
arr = comManager.read(2)
h = arr[0]*256 + arr[1]
pixelformat_len = comManager.read(1)
pixelformat = comManager.read(pixelformat_len[0])
arr = comManager.read(4)
imageLen = arr[0]*256*256*256 + arr[1]*256*256 + arr[2]*256 + arr[3]
print ("image Len: %d" % imageLen, flush=True);
print('Image format is ' + pixelformat.decode('ASCII'))
if ( imageLen > 0 ):
image = bytearray()
startTime = time.time();
timeout = 0
while (imageLen != len(image)):
image += comManager.read(imageLen-len(image))
print (" Total Read Len:%d bytes" % len(image), flush=True)
# check timeout
if ( time.time() > (startTime + READ_TIMEOUT)):
print("Test Failed: Timeout\n", flush=True);
timeout = 1
break
if (timeout == 1):
continue
print ("All image data read", flush=True);
imgConverter.convert(image, "Image.png", w, h, pixelformat.decode('ASCII'))
image = cv2.imread("image.png")
cv2.imshow(" ", image)
cv2.waitKey(1)
#exit(0)效果演示:



我要赚赏金
