在我们使用openmv中的神经网络时,在新的版本里是没有nn的库给你调用的,需要在老版本里才有,百度云链接:https://pan.baidu.com/s/1bgLiLMxyqqL9X3h5dN8cZA 提取码:behn (光这个能不能点个赞咧)
本文的数字识别的及基础使用可看这个视频OpenMV Lenet识别数字 | 星瞳科技
nn
模块用于神经网络。nn_class对象由 net.search() 返回。classnn.nn_class请调用 net.search() 来创建这个对象与神经网络算法.
神经网络是受神经元启发的,对于神经元的研究由来已久,1904年生物学家就已经知晓了神经元的组成结构。一个神经元通常具有多个树突,主要用来接受传入信息;而轴突只有一条,轴突尾端有许多轴突末梢可以给其他多个神经元传递信息。轴突末梢跟其他神经元的树突产生连接,从而传递信号。这个连接的位置在生物学上叫做“突触”。在这里可以参考高中生物关于神经元信息传输与脉冲刺激兴奋的关系。
1949年心理学家Hebb提出了Hebb学习率,认为人脑神经细胞的突触(也就是连接)上的强度上可以变化的。于是计算科学家们开始考虑用调整权值的方法来让机器学习。这为后面的学习算法奠定了基础。
1958年,计算科学家Rosenblatt提出了由两层神经元组成的神经网络。他给它起了一个名字–感知器( Perceptron )。
1986年,Rumelhar和Hinton等人提出了反向传播( Backpropagation ,BP)算法,这是最著名的一个神经网络算法。
组成
多层神经网咯主要由三部分组成:输入层(input layer), 隐藏层 (hidden layers), 输入层 (output layers)。
每层由单元(units)组成, 输入层(input layer)是由训练集的实例特征向量传入,经过连接结点的权重(weight)传入下一层,一层的输出是下一层的输入。 隐藏层(hidden layers)的个数可以是任意的,输入层有一层,输出层(output layers)有一层。每个单元(unit)也可以被称作神经结点。上图为2层的神经网络(一般输入层不算)。
一层中加权的求和,然后根据非线性方程转化输出。作为多层向前神经网络,理论上,如果有足够多的隐藏层(hidden layers) 和足够大的训练集, 可以模拟出任何方程。
神经网络可以用来解决分类(classification)问题,也可以解决回归( regression )问题。
单层到多层的神经网络
由两层神经网络构成了单层神经网络,它还有个别名——— 感知机(Perceptron)。在3个输入,连接线的权值分别是 w1, w2, w3。将输入与权值进行乘积然后求和,作为 z单元的输入,如果 z 单元是函数 g ,那么就有 z = g(a1 * w1 + a2 * w2 + a3 * w3) 。
在多层神经网络中,只不过是将输出作为下一层的输入,一样是乘以权重然后求和。
nn_class.rect()
返回一个nn_class的边界框的矩形元组(x,y,w,h),用于像 image.draw_rectangle()
等 image
方法。
nn_class.x()
返回nn_class的边界框的x坐标(int)。
您也可以通过索引 [0]
取得这个值。
nn_class.y()
返回nn_class的边界框的y坐标(int)。
您也可以通过索引 [1]
取得这个值。
nn_class.w()
返回nn_class的边界框的w坐标(int)。
您也可以通过索引 [2]
取得这个值。
nn_class.h()
返回nn_class的边界框的h坐标(int)。
您也可以通过索引 [3]
取得这个值。
nn_class.index()
返回nn类检测的索引(int)。
您也可以通过索引 [4]
取得这个值。
nn_class.value()
返回nn类检测的值(float)。
您也可以通过索引 [5]
取得这个值。
classnn.load(path)
将神经网络从 .network
二进制文件加载到内存中。 神经网络的层/权值/偏置/等。存储在MicroPython堆上。 返回一个可以在图像上进行操作的Net对象。
net.forward(image[, roi[, softmax=False[, dry_run=False]]])
在图像roi上运行网络(必要时自动缩放)并返回神经网络分类结果的浮点值列表。
roi
是感兴趣区域的矩形元组(x,y,w,h)。如果未指定,则它等于图像矩形。仅运算 roi
中的像素。
如果 softmax
为True,则列表中所有的输出总和为1。否则,列表中的任何输出都可以在0和1之间。
将 dry_run
设置为True以打印出正在执行的网络层而不是实际执行它们。这是为了调试debug。
net.search(image[, roi[, threshold=0.6[, min_scale=1.0[, scale_mul=0.5[, x_overlap=0[, y_overlap=0[, contrast_threshold=1[, softmax=False]]]]]]]])
以滑动窗口方式在图像roi上运行网络。 网络检测器窗口以多种比例滑过图像。
返回神经网络检测结果的 nn_class 对象列表。
roi
是感兴趣区域的矩形元组(x,y,w,h)。如果未指定,则它等于图像矩形。仅运算 roi
中的像素。
在图像中的区域上运行之后,将最大检测值超过 threshold
的对象添加到输出列表中。
min_scale
控制网络模型的缩放比例。在默认值下,网络不会缩放。但是,值为0.5将允许用于检测图像大小为50%的对象…
scale_mul
控制测试多少个不同的比例。滑动窗口方法的工作原理是将默认比例1乘以 scale_mul
,
并且结果需要大于 min_scale
。 scale_mul
的默认值0.5,测试每个比例变化减少50%。 但是,0.95的值仅为5%的缩小量。
x_overlap
控制与滑动窗口的下一个检测区域重叠的百分比。值为零表示没有重叠。值为0.95意味着95%重叠。
y_overlap
控制与滑动窗口的下一个检测区域重叠的百分比。值为零表示没有重叠。值为0.95意味着95%重叠。
contrast_threshold
控制跳过图像低对比度区域的阈值。在图像中的某个区域上运行nn之前,将在该区域上计算标准偏差,如果标准偏差低于 contrast_threshold
,则跳过该区域。
如果 softmax
为True,则列表中所有的输出总和为1。否则,列表中的任何输出都可以在0和1之间。
# LetNet Example 直接使用openmv与电脑连接就可以使用了
import sensor, image, time, os, nn
sensor.reset() # Reset and initialize the sensor.
sensor.set_contrast(3)
sensor.set_pixformat(sensor.GRAYSCALE) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240)
sensor.set_windowing((128, 128)) # Set 128x128 window.
sensor.skip_frames(time=100)
sensor.set_auto_gain(False)
sensor.set_auto_exposure(False)
# Load lenet network
net = nn.load('/lenet.network')
labels = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
clock = time.clock() # Create a clock object to track the FPS.
while(True):
clock.tick() # Update the FPS clock.
img = sensor.snapshot() # Take a picture and return the image.
out = net.forward(img.copy().binary([(150, 255)], invert=True))
max_idx = out.index(max(out))
score = int(out[max_idx]*100)
if (score < 70):
score_str = "??:??%"
else:
score_str = "%s:%d%% "%(labels[max_idx], score)
img.draw_string(0, 0, score_str)
print(clock.fps()) # Note: OpenMV Cam runs about half as fast when connected
# to the IDE. The FPS should increase once disconnected.
在进行通信时最好对于C语言有较好的基础,不然会难以进行对于通信模块的准备。
openmv-与stm32代码调整
# LetNet Example 直接使用openmv与电脑连接就可以使用了
import sensor, image, time, os, nn
import pyb from uart
sensor.reset() # Reset and initialize the sensor.
sensor.set_contrast(3)
sensor.set_pixformat(sensor.GRAYSCALE) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240)
sensor.set_windowing((128, 128)) # Set 128x128 window.
sensor.skip_frames(time=100)
sensor.set_auto_gain(False)
sensor.set_auto_exposure(False)
uart(1,115200)#这里要进行注意,你的stm32的串口通信使用的时是什么如:调用UART1就是用1的
# Load lenet network
net = nn.load('/lenet.network')
labels = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',0x5B]
clock = time.clock() # Create a clock object to track the FPS.
while(True):
clock.tick() # Update the FPS clock.
img = sensor.snapshot() # Take a picture and return the image.
out = net.forward(img.copy().binary([(150, 255)], invert=True))
max_idx = out.index(max(out))
score = int(out[max_idx]*100)
if (score < 70):
score_str = "??:??%"
else:
score_str = "%s:%d%% "%(labels[max_idx], score)
img.draw_string(0, 0, score_str)
print(clock.fps())
uart.write(labels[max_idx]) # Note: OpenMV Cam runs about half as fast when connected
# to the IDE. The FPS should increase once disconnected.
(使用IIC,或SPI,无线电wifi通信也是可以的)
如果需要进行WiFi与openmv通信最好先去看这个教程视频。WIFI编程对OpenMV远程调试 | 星瞳科技 (singtown.com)
在这里需要外加模块或板子,如:esp8266(adriuno)
在stm32中使用串口通信用于接收opennmv传过来的数据,在这里要特别强调,它传过来的字符串,要自己进行对应的字符转换才能进行解码。
//USART1 全局中断服务函数
void USART1_IRQHandler(void)
{
char com_data;
static u8 RxBuffer1[10]={0};
static u8 RxFlag1 = 0;
u8 temp;
if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //接收中断
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志
com_data = USART_ReceiveData(USART1);
if(flag0==0)
{
if(com_data!=' ')
{
RxBuffer1[RxFlag1]=com_data;
RxFlag1++;
}
else if(com_data==' ')
{
sum=RxBuffer1[1];
printf("sum is %c\n", sum);
flag0=1;
RxFlag1=0;
}
}
else
{
if((com_data>47)&&(com_data<58))
{
RxBuffer1[RxFlag1]=com_data;
RxFlag1++;
}
else if(com_data==' ')
{
if(RxFlag1==1)
{
temp=(RxBuffer1[0]-48);
}
else if(RxFlag1==2)
{
temp=(RxBuffer1[0]-48)*10+(RxBuffer1[1]-48);
}
else if(RxFlag1==3)
{
temp=(RxBuffer1[0]-48)*100+(RxBuffer1[1]-48)*10+(RxBuffer1[2]-48);
}
Cx=temp;
printf("Cx is %d\n", Cx);
RxFlag1=0;
}
}
// else if(RxState==1)
// {
// if((com_data>47)&&(com_data<58))
// {
// RxBuffer1[RxFlag1]=com_data;
// RxFlag1++;
// }
// else if(com_data==' ')
// {
// if(RxFlag1==1)
// {
// Cw=(RxBuffer1[0]-48);
// }
// else if(RxFlag1==2)
// {
// Cw=(RxBuffer1[0]-48)*10+(RxBuffer1[1]-48);
// }
// else if(RxFlag1==3)
// {
// Cw=(RxBuffer1[0]-48)*100+(RxBuffer1[1]-48)*10+(RxBuffer1[2]-48);
// }
// RxFlag1=0;
// printf("Cw is %d\n", Cw);
// RxState=0;
// }
// }
}
}
在这里我直接先给出中断函数的代码,其他的配置就和一般的stm32 串口通信的相同。在这里可以解释下为什么openmv那边传过来的字符串,因为openmv虽然是有自带stm32芯片处理,但为了后续更好的进行简单化使用就用python尽心那个了封装,而在python中在未规定指定的传出数据时都是默认传输字符串。剩下的就是在串口助手那里看是否有数据过来