- 2024-12-19
-
回复了主题帖:
测评入围名单: NXP MCX A系列 FRDM-MCXA156开发板
个人信息无误,确认可以完成测评分享计划.
- 2024-12-09
-
发表了主题帖:
《计算机视觉之PyTorch数字图像处理》----解读“图像分类和图像分割”
要说起图像分类和图像分割,还要从一个有转折性意义的比赛讲起。
在2012年的ImageNet大规模分类比赛中,AlexKrizhevsky在Hinton的指导下使用其构建的卷积神经网络—AlexNet取得冠军。该AlexNet的分类精度较之以前的手工构建特征的再分类方法提高了近50%,从而使得图像分类任务取得了重大的突破。随后,卷积神经网络一路突飞猛进, 在图像分类上迅速达到了人的识别精度,并在其他的图像和非图像任务上也取得了极大的进步。
单就图像分类来讲,它是模式识别、机器学习和人工智能的重要任务之一,它由图像处理研究开始,始终是研究的热点之一。
随着卷积神经网络成为研究的热点,基于卷积神经网络的各种模型在不断地刷新分类精度。
就完成一个分类任务而言,完全从头开始进行模型的构建和训练并非是一个好方法。充分利用已有的模型,在进行评估后,再进行调节和修改才更合理。在torchvision库中,已集成了许多经典的分类网络模型,可以通过函数的调用即可创建相应的模型,从而可以免去自行搭建的麻烦。令人更为心喜的是这些模型中大多数都提供了已训练好的参数,并可在创建模型时同步加载,让模型即时可用,这些模型均位于torchvision.models包下。
在预训练模型的使用,可所用多种模型进行预测,以三趾 树懒(three-toed sloth)为例,三种模型的预测结果为:
resnet18的预测结果是:three-toed sloth, ai, Bradypus tridactylus,置信度是:93.9%
shufflenet的预测结果是:three-toed sloth, ai, Bradypus tridactylus,置信度是:99.9%
mobilenetv3的预测结果是:three-toed sloth, ai, Bradypus tridactylus,置信度是:75.0%
可见其置信度是非常高的,是可以投入应用的。
图1 三趾树懒
图像分割是图像处理的一项重要任务,图像分割可以看作是一种特殊的图像分类——逐像素的分类。
由于卷积神经网络在图像分类任务上的成功,将卷积网络进行适当的改进就能用于图像分割任务。在加入上采样和不同层次的特征后,卷积神经网络相较于其他方法能够在图像分割上取得更好的效果。
相较于分类网络,分割网络在数据集的制作、数据增强方法、损失函数、模型评估等都有自身独特的特性。
在经典的图像处理中,图像分割一般是基于单个像素值或包含一定邻域内的全部像素进行类别的判断。
经典方法存在的问题主要表现为分割结果较为破碎,边界不够圆滑,分割结果不准确。随着深度学习在分类上的成功,深度神经网络成为一种很好的特征提取器,能够生成比像素值更好的识别特征。因此,在对分类神经网络的结构进行改进后,能直接输出一张与输入图像宽高尺寸相同的张量,从而完成端到端的训练。
图2是一个进行实例分割的结果,可见其完成质量是较高的。
图2 原始图像 分割结果
- 2024-12-05
-
发表了主题帖:
《计算机视觉之PyTorch数字图像处理》----解读“自动梯度与神经网络”
在说明自动梯度与神经网络这个问题之前,先要介绍一下计算机视觉研究的方法,它主要分为三类,即传统方法、机器学习方法即深度学习方法。
传统方法
所谓“传统方法”是一种基于经典图像处理技术的方法,主要包括边缘检测、角点检测、纹理分析和状态描述等。传统方法通常需要手动设计特征提取和分类算法,它对图像质量和环境变化比较敏感、泛化性较差,只有在较为理想的条件下,才能获得满意的效果,但它对其它方法的研究具有较大的启发意义,是这方面的研究基点。
机器学习方法
所谓“机器学习方法”是一种通过数据自动学习其模式和规律的方法,可用于多样化的数据分析任务,该方法常用于图像分类、目标检测和图像法国等任务,在应用时常与图像处理方法结合所用。
深度学习方法
所谓“深度学习方法”,则是一种基于神经网络的机器学习方法,它通过多层神经网络来学习图像的高级特征和表示,比如卷积神经网络CNN的应用就已成为图像分类、目标检测和图像分割等的主流方法,并取得了接近人类视觉认知的水平。
有了以上的基本认识,再回到当初所提的问题上来。
所谓“自动梯度”是PyTorch所提供的最核心的功能,可对神经网络的梯度进行求解及反向传播,并对神经网络的权重加以优化。
自动梯度的实现是依托于torch.autograd包,可实现任何张量函数的求导计算。
在PyTorch中,是使用计算图来组织变量,且计算图是动态的。每次自动梯度的计算都是以最近一次计算图的前向传播为准。
所谓“前向传播”是指输入张量在按照函数的计算图进行运算时,其得到输出结果的这个过程被称为前向传播。
而将输出结果沿计算图前向传播的反方向梯度计算并计算到计算图输入的求解梯度过程称为“反向传播”。
在梯度计算中,使用梯度下降法可求解函数极小值,当梯度接近0或者函数值不再明显减小时,即可认为达到了极小值。
图1 用梯度下降法求解函数极小值
自动梯度不仅计算单变量的梯度,还能对多变量函数进行梯度计算,图2是对sin(x)函数的拟合过程。
图2 自动梯度拟合多元函数
对sin(x)函数进行拟合代码及结果如下:
import torch as tc
import visdom
vis=visdom.Visdom()
lossline=vis.line([None]) #动态记录损失的变化
pi =tc.deg2rad(tc.tensor(180.0)) #得到pi的弧度值
x = tc.linspace(-pi, pi, 2000) #在-pi到pi平均间隔采2000个样
y=tc.sin(x) #计算sin(x)的值
#需要学习多项式的系数
a = tc.randn(1, requires_grad=True)
b = tc.randn(1, requires_grad=True)
c = tc.randn(1, requires_grad=True)
d = tc.randn(1, requires_grad=True)
e = tc.randn(1, requires_grad=True)
f = tc.randn(1, requires_grad=True)
#设置训练轮数和学习速率(梯度更新比率)
epoch=80000
learning_rate = 0.55*1e-7
for t in range(epoch):
# 前向计算,使用5次多项式
y_pred = a + b * x + c * x ** 2 + d * x ** 3+ e * x**4 +f * x**5
# 计算每一点处拟合值与真实值的差
# 计算误差的平方和得到一个尺寸为(1,)的标量,作为损失
loss = (y_pred - y).pow(2).sum()
# 每100轮打印的值
if t % 100 == 99:
print(t, loss.item())
#将训练过程中的损失变化进行可视化
vis.line([loss.item()],[t],win=lossline,update='append')
#调用loss张量的backward方法,沿计算图反向求导
#计算出所有张量中属性requires_grad=True的梯度
#完成计算后a.grad,b.grad,c.grad,d.grad,e.grad,f.grad保存了梯度
loss.backward()
# 手动进行参数的梯度下降,由于参数都是可求导的
#使用tc.no_grad(),放弃对所包含内容加入到计算图
with tc.no_grad():
a -= learning_rate * a.grad
b -= learning_rate * b.grad
c -= learning_rate * c.grad
d -= learning_rate * d.grad
e -= learning_rate * e.grad
f -= learning_rate * f.grad
#在更新完参数后,将参数的梯度手动置0
a.grad = None
b.grad = None
c.grad = None
d.grad = None
e.grad = None
f.grad = None
#打印学习到的函数
print(f'结果: y = {a.item()} + {b.item()} x + {c.item()} x^2 + {d.item()} x^3+{e.item()}x^4+{f.item()}x^5')
py=tc.stack([y,y_pred],0).T #整理y=sin(x)的值和预测的值y_pred
#绘制sin(x)和学习函数
vis.line(py,x)
#输出:
结果: y = -0.007337956223636866 + 0.9179902672767639 x + 0.004045205190777779 x^2 + -0.12921814620494843 x^3+-0.00039120070869103074x^4+0.0035445974208414555x^5
通常神经网络是由许多结构相似的模块所组成,这些结构通常也称为层。
在图像处理中涉及的层有卷积层、池化层、填充层及全连接层。
在PyTorch中,由torch.nn包提供了许多在深度学习中使用频率很高的一些层。利用这些层,则可以方便、快捷的构建起深度学习的模型。
此外,PyTorch也提供自定层的方法,可以通过继承torch.nn包中的Module类,进行层的自定义,增加了PyTorch的拓展性。
也就是说,有了PyTorch这个工具,就为深度学习打开了探索之门。
-
回复了主题帖:
【翌创ET6001测评】LCD5110屏显示驱动
sx-liumy1234 发表于 2024-12-5 09:37
收集的资料很全面,值得学习学习,收藏了,谢谢提供资料
感谢支持!!!
-
回复了主题帖:
【翌创ET6001测评】LCD5110屏显示驱动
jobszheng5 发表于 2024-12-4 22:49
这个屏是存在了多少年了啊
老有时间啦!!!
- 2024-12-04
-
发表了主题帖:
【翌创ET6001测评】LCD5110屏显示驱动
Nokia5110显示屏是早期诺基亚手机所使用的显示屏,它采用SPI接口的方式来工作,该屏与开发板的连接关系为:
SCL---P22
SDA---P23
RST---P24
DC ---P25
CS ---P21
BLK---VDD
使用引脚输出高低电平的语句定义为:
#define LCD_SCLK_Set GPIO_WritePin(GPIO2, GPIO_PIN_02, SET) //CLK
#define LCD_SCLK_Clr GPIO_WritePin(GPIO2, GPIO_PIN_02, RESET)
#define LCD_SDIN_Set GPIO_WritePin(GPIO2, GPIO_PIN_03, SET) //DIN
#define LCD_SDIN_Clr GPIO_WritePin(GPIO2, GPIO_PIN_03, RESET)
#define LCD_RST_Set GPIO_WritePin(GPIO2, GPIO_PIN_04, SET) //RES
#define LCD_RST_Clr GPIO_WritePin(GPIO2, GPIO_PIN_04, RESET)
#define LCD_DC_Set GPIO_WritePin(GPIO2, GPIO_PIN_05, SET) //DC
#define LCD_DC_Clr GPIO_WritePin(GPIO2, GPIO_PIN_05, RESET)
#define LCD_CS_Set GPIO_WritePin(GPIO2, GPIO_PIN_01, SET) //CS
#define LCD_CS_Clr GPIO_WritePin(GPIO2, GPIO_PIN_01, RESET)
配置引脚为输出功能的函数为:
void LCD_CONFIG(void)
{
IOC_Init_TypeDef init;
IOC_ConfigStructInit(&init);
init.mode = IOC_AF_MODE_3;
init.dir = GPIO_DIR_OUT;
init.pull = IOC_PULL_NONE;
IOC_Config(IOC_PIN_GPIO_PLL_REF, &init);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_01);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_02);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_03);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_04);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_05);
}
该显示屏的初始化函数为:
static void LCD_init(void)
{
LCD_RST_Clr;
Delay(1);
LCD_RST_Set;
LCD_CS_Clr;
Delay(1);
LCD_CS_Set;
Delay(1);
LCD_write_byte(0x21, 0);
LCD_write_byte(0xc8, 0);
LCD_write_byte(0x06, 0);
LCD_write_byte(0x13, 0);
LCD_write_byte(0x20, 0);
LCD_clear();
LCD_write_byte(0x0c, 0);
LCD_CS_Clr;
LCD_BLK_Set;
}
实现清屏处理的函数为:
static void LCD_clear(void)
{
unsigned int i;
LCD_write_byte(0x0c, 0);
LCD_write_byte(0x80, 0);
for (i=0; i<504; i++)
LCD_write_byte(0, 1);
}
实现字符显示功能的函数为:
static void LCD_write_char(unsigned char c)
{
unsigned char line;
c -= 32;
for (line=0; line<6; line++)
LCD_write_byte(font6x8[c][line], 1);
}
实现字符串显示功能的函数为:
static void LCD_write_english_string(unsigned char X,unsigned char Y,char *s)
{
LCD_set_XY(X,Y);
while (*s)
{
LCD_write_char(*s);
s++;
}
}
显示显示功能测试的主程序为:
int main(void)
{
EVB_LEDInit();
LCD_CONFIGt();
LCD_init();
LCD_clear();
LCD_write_english_string(16,0,"AT32L021");
LCD_write_english_string(16,2,"NOKIA_5110");
while(1);
}
经程序的编译与运行,其显示效果如下图所示。
显示效果图
- 2024-11-30
-
发表了主题帖:
【翌创ET6001测评】AT24CXX系列器件测试中的问题
本帖最后由 jinglixixi 于 2024-12-4 21:28 编辑
先前已完成了W25QXX系列器件的读写测试,尽管例程是针对W25X40所准备的,但对于W25Q16来说依然有效。
为此打算也对AT24CXX系列器件进行一下读写测试,虽然厂家提供的例程是针对AT24C64的,由于手头仅有AT24C02,且2个芯片同属于一个系列,直至是在容量有所差异,通过测试的可能性还是有的。
例程所指定的引脚连接关系为:
I2C0_IC_SCL----(J9-4)
I2C0_IC_SDA---(J9-3)
图1 实物连接
测试的主程序为:
int main(void)
{
I2C_InitTypeDef init;
uint32_t i, j;
uint32_t cnt;
uint32_t len;
uint32_t chipaddr;
I2C0_Type *I2Cx = I2C0;//use I2C0
UNUSED(len);
//initial UART0
UART0_printInit();
printf("\n\rI2C at24c64d demo start.\n\r");
I2C0_pinmux_init();
I2C_DeInit(I2Cx);
I2C_StructInit(&init);
I2C_Init(I2Cx, &init);
I2C_SetMasterTargetAddress(I2Cx, AT24_ADDRESS);
I2C_SetRXTL(I2Cx, 1);
I2C_SetTXTL(I2Cx, 0);
I2C_Enable(I2Cx);
//page write&read for all chip
cnt = AT24C64_ALL_SIZE / AT24C64_PAGE_SIZE;
for(i=0; i<cnt; i++){
//initial tx buffer
for(j=0; j<AT24C64_PAGE_SIZE; j++)
txBuf[j] = (uint8_t)(AT24C64_PAGE_SIZE*i+j+0x22);
memset(rxBuf, 0, AT24C64_PAGE_SIZE);
//write one page
len = at24_writepage(I2Cx, txBuf, AT24C64_PAGE_SIZE*i);
//read back one page
len = at24_readpage(I2Cx, rxBuf, AT24C64_PAGE_SIZE*i);
//do check txbuffer and rxbuffer
if(memcmp(txBuf, rxBuf, AT24C64_PAGE_SIZE)){
printf("read page check error!\n\r");
break;
}
}
//AT24C64D write byte
at24_writebyte(I2Cx, (uint8_t *)"d", 0x102);
at24_writebyte(I2Cx, (uint8_t *)"a", 0x103);
memset(rxBuf, 0, sizeof(rxBuf));
//AT24C64D read byte start 0x100
at24_readbyte(I2Cx, &(rxBuf[0]), 0x100);
//AT24C64D seqence read for continue data read
at24_readbytes_seq(I2Cx, &(rxBuf[1]), 12);
//print and check write&read
printf("Receive data(offset:0x%04x) : %02x %02x %02x %02x %02x %02x %02x %02x "\
"%02x %02x %02x %02x %02x %02x %02x %02x\n\r", 0x100,
rxBuf[0], rxBuf[1], rxBuf[2], rxBuf[3],
rxBuf[4], rxBuf[5], rxBuf[6], rxBuf[7],
rxBuf[8], rxBuf[9], rxBuf[10], rxBuf[11],
rxBuf[12], rxBuf[13], rxBuf[14], rxBuf[15]);
for(j=0; j<AT24C64_ALL_SIZE; j++)
g_txBuf[j] = (uint8_t)(j+0x88);
memset(g_rxBuf, 0, AT24C64_PAGE_SIZE);
//write all
chipaddr = 0x10;
len = AT24C64_ALL_SIZE-chipaddr;
at24_writebytes(I2Cx, g_txBuf, len, chipaddr);
at24_readbytes(I2Cx, g_rxBuf, len, chipaddr);
//do check txbuffer and rxbuffer
if(memcmp(g_txBuf, g_rxBuf, len)){
printf("all chip check error!\n\r");
}
I2C_Disable(I2Cx);
I2C_DeInit(I2Cx);
do {
__asm volatile ("nop");
}while(1);
}
在完成模块连接后,经程序的编译与运行,其测试结果如图2所示,说明尝试失败。
图2 测试结果
由于AT24C64与AT24C02在存储容量上有较大的差异,自然在一些参数上会有所差异,但相对来讲,AT24CXX系列器件的读写要比W25QXX系列器件的容易,因为W25QXX系列器件在写入前,必须对待写单元进行擦除,而AT24CXX系列器件则无需此操作。
为增加测试的成功率,又将程序改为对指定单元的读写测试,经测试其结果如图2所示,至此说明尝试无效。
指定单元读写测试程序:
for(j=0; j<8; j++)
txBuf[j] = (uint8_t) (j+0x30);
g=at24_writebytes(I2Cx, txBuf, 8, 0x08);
printf("%d \n\r",g);
printf("write data: %02x %02x %02x %02x %02x %02x %02x %02x "\
"\n\r",
txBuf[0], txBuf[1], txBuf[2], txBuf[3],
txBuf[4], txBuf[5], txBuf[6], txBuf[7]);
g=at24_readbytes(I2Cx, rxBuf, 8, 0x08);
printf("%d \n\r",g);
printf("read data: %02x %02x %02x %02x %02x %02x %02x %02x "\
"\n\r",
rxBuf[0], rxBuf[1], rxBuf[2], rxBuf[3],
rxBuf[4], rxBuf[5], rxBuf[6], rxBuf[7]);
图3 测试结果
由此可知,用例程是无法对AT24C02进行读写的,至于对AT24C64是否有效,只有留待具备其测试条件者来完成了。
- 2024-11-29
-
发表了主题帖:
【翌创ET6001测评】步进电机驱动控制
本帖最后由 jinglixixi 于 2024-11-29 12:57 编辑
步进电机是一种常用的执行器件,使用它能进行精准的定位及转速调节等工作。一个简单的步进电机驱动电路主要由步进电机、驱动电路及微控制器所构成。
为驱动步进电机,可使用图1所示连接方式。
图1 连接方式
值得指出的是,尽管在使用外部电源适配器的情况下,在开发板上可得到5V的工作电源,但经过实际测试它是无法驱动步进电机的,故需要额外的5V电源向步进电机供电。
为了驱动步进电机,除了硬件方面的准备,还需必要的软件配合。
要编写步进电机驱动程序主要分为以下几步:
1)分配引脚
步进电机与开发板的连接关系为:
MA---P21
MB---P22
MC---P23
MD---P24
2)高低电平的输出
为便于输出高低电平,所作的定义语句为:
#define MAL GPIO_WritePin(GPIO2, GPIO_PIN_01, RESET)
#define MAH GPIO_WritePin(GPIO2, GPIO_PIN_01, SET)
#define MBL GPIO_WritePin(GPIO2, GPIO_PIN_02, RESET)
#define MBH GPIO_WritePin(GPIO2, GPIO_PIN_02, SET)
#define MCL GPIO_WritePin(GPIO2, GPIO_PIN_03, RESET)
#define MCH GPIO_WritePin(GPIO2, GPIO_PIN_03, SET)
#define MDL GPIO_WritePin(GPIO2, GPIO_PIN_04, RESET)
#define MDH GPIO_WritePin(GPIO2, GPIO_PIN_04, SET)
3)配置引脚工作模式
要驱动步进电机工作,必须向各引脚按时序要求来输出高低电平,其引脚工作模式的配置函数为:
void bjdj_CONFIG(void)
{
IOC_Init_TypeDef init;
IOC_ConfigStructInit(&init);
init.mode = IOC_AF_MODE_3;
init.dir = GPIO_DIR_OUT;
init.pull = IOC_PULL_NONE;
IOC_Config(IOC_PIN_GPIO_PLL_REF, &init);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_01);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_02);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_03);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_04);
}
4)配置延时函数
配置延时函数的作用在步进电机的驱动中十分重要,它控制着步进电机运转的快慢。
对于步进电机来说其速度是与驱动脉冲相有关的,但也并非脉冲越快,电机的转速就越快。因为电机属机械器件,要建立相应的磁场以达到相应的扭矩才能使电机转动。过快的脉冲只会使电机在原地震颤和抖动,而无法旋转。
5)控制电机旋转方向
对于4相5线式步进电机来讲,可通过8个节拍的脉冲序列来控制其正反转。
正转的驱动函数为:
void zx(int n)
{
unsigned char X,Y;
for(X=0;X<64;X++)
{
for(Y=0;Y<8;Y++)
{
MDL;
MAH; //A
delay(n);
MBH; //AB
delay(n);
MAL; //B
delays(n);
MCH; //BC
delay(n);
MBL; //C
delay(n);
MDH; //CD
delay(n);
MCL; //D
delay(n);
MAH; //DA
delay(n);
}
}
}
反转的驱动函数为:
void fx(int n)
{
unsigned char X,Y;
for(X=0;X<64;X++)
{
for(Y=0;Y<8;Y++)
{
MDH;
MAH; //A
delay(n);
MAL; //AB
delay(n);
MCH; //B
delay(n);
MDL; //BC
delay(n);
MBH; //C
delay(n);
MCL; //CD
delay(n);
MAH; //D
delay(n);
MBL; //DA
delay(n);
}
}
}
6)控制电机运行
控制电机运行的主程序为:
int main(void)
{
char f,m,i;
EVB_LEDInit();
bjdj_CONFIG();
MAL;
MBL;
MCL;
MDL;
delay(1);
f=0;
m=5;
for(i=0;i<m;i++)
{
if(f==0) fx(1);
else zx(1);
}
while (1)
{
GPIO_TogglePin(GPIO_LED_PORT, GPIO_LED_PIN);
Delayp(0x5FFFFF);
}
}
经程序的编译与运行,则可见到步进电机开始转动见图2所示,说明程序测试成功。
图2 运行状态
演示视频:
[localvideo]119bff447b78fff494e0897aff0d4674[/localvideo]
- 2024-11-27
-
发表了主题帖:
《计算机视觉之PyTorch数字图像处理》----解读PyTorch与图像处理的关系
在《计算机视觉之PyTorch数字图像处理》这本书中,PyTorch是一种至关重要的设计工具,也是实现图像处理的重要手段。
在许多年以前,曾讲授过以photoshop为核心的图像处理课,其主要任务就是利用photoshop所提供的各种选取工具对提取的图片内容进行各种拼接、变换及特效处理来完成作品设计。其应用的反向主要涉及课件界面的制作、网页素材的加工制作、装帧封面的设计、海报设计及旅游景点的广告设计等。
尽管可以用photoshop完成各种作品的效果设计与制作,但对photoshop是如何来实现这些处理的却是一头雾水,也无从去寻找答案。
后来在设计中又遇到了色差分析问题,才了解到针对色彩空间有多种色彩模式标准并可在不同的色彩模式间进行转换。例如RGB模式就可以转换为相应的Lab模式。 色差分析仪就是以Lab模式进行判别的,并通过分析样本与标准样本的比对来给出色差状况及分析结论的可信度。
在实践中发现,要想得到一个理想的色彩模块变换公式是十分困难的,要想得到一个与photoshop一致的变换结果更是可望而不可及,只能获得一个与之变化趋势相近的结果。
通过阅读这本书,终于揭开了这方面的一些端倪。原来在以PyTorch为实践工具的情况下,它是沿着这样一条途径来进行图像处理,即图像中的数据是以张量的方式来存储和处理的,这里所说的张量可视为通常所说的数组。
这样在进行数据处理时就可以快速进行定位的需要,而所谓的数据处理可视为为了达到某种图像处理效果的数据变换。
那么图像数据又是如何获取和保存的呢?
原来PyTorch不但提供进行数据处理的各种运算功能,还提供了打开图像文件并将数据存入数组(张量)的功能及将变换处理后的数据保存到图像文件的功能,这样就确保了它对图像处理的可靠支持。也就是说PyTorch与图像处理是紧密相关的,两者是属于一种不可或缺的关系。
我们知道图像是用来表现二维空间的,需由二维数组来存储其数据,此时其表现的图像是灰度等级的。要表现彩色的图像,通常需要三维数组来实现。
有人会说那不对呀,在单片机或ARM上存储彩色的图像不是用二维数组不就可以吗?
其实这是因为它采用了压缩存储的方式,即把RGB的3种色彩数据放到了2个或3个字节数据中。对于3字节方式,每个字节对应一种色彩;对于2字节方式,则是以565的占比来分配2个字节,即红色占用5位,绿色占用6位,蓝色占用5位,共计16位2个字节。
在photoshop中,使用渐变效果可制作各种立体效果,那在PyTorch是如何来实现的呢?
以线性渐变为例,它是对某一行的数据进行由小到大或有大到小的变换处理。
其实现的程序为:
d=[i for i in range(256)]*100 #产生图像数据
imgd=bytes(d) #转化为字节串
img=Image.frombytes('L',(256,100),imgd) #根据图像数据,生成宽256高100的渐变灰度图像
img.save('gb.png') #保存图像为gb.png
图1 灰度渐变效果
在photoshop中,蒙版是一种使遮挡层下的图层呈现显示状态的工具,其实现的方式如图2所示。
图2 蒙版处理
此外,使用PyTorch可实现多种色彩空间的模式变换,涉及的有灰度空间、HSI色彩空间、HSV色彩空间、XYZ空间及Lab空间等。
在数据处理方面,则涉及图像的旋转/翻转、缩放、裁剪等。
通过本书的阅读,终于圆了多年以来想了解photoshop如何进行图像处理的奥秘。
-
回复了主题帖:
《计算机视觉之PyTorch数字图像处理》----初品之感受
freebsder 发表于 2024-11-25 17:34
谢谢分享,期待后续深入解读。
哈哈,努力!
- 2024-11-25
-
回复了主题帖:
《计算机视觉之PyTorch数字图像处理》----初品之感受
hellokitty_bean 发表于 2024-11-24 22:57
请问楼主,这个版本是什么年份的?。。。。。。。谢谢了先
2024年9月第一版
- 2024-11-24
-
发表了主题帖:
《计算机视觉之PyTorch数字图像处理》----PyThon再认识
本帖最后由 jinglixixi 于 2024-11-24 13:33 编辑
《计算机视觉之PyTorch数字图像处理》这本书不仅是一本讲述理论知识的书,还是一本将理论知识转化为实践应用的书,并向读者推荐了一款有效的实践工具---Python。
在没得到这本书之前,自己也曾因为开发板测评的需要,选用过开发板所依托的开发工具Python,并随着开发板的不同,分别在Window和Linux的系统环境下用到它,进而认识到它是一种可以跨平台进行开发的工具。
此外,在使用中发现它是一种采用类似于Basic的采用解释性运行机制的开发工具。
当然,伴随安装选择的不同,它是有两种不同执行方式的,即一种是以单条指令的方式来执行,它主要适于学习和测试;另一种则是以文件的方式来运行,自然这种方式的执行效率会更高。
选取Python安装,是以指令的方式执行,见图1所示。
图1 即时执行方式运行
选取IDLE安装,是以.py文件的方式运行,见图2和图3所示。
图2 创建.py文件
图3 文件方式运行
在阅读此书之后,才发现它的强大,以及近年来它的影响之深。
Python一词的原意和标志一样,意为“巨蟒”。其发明人是一位荷兰人名为Rosum,因其贡献被尊称为“Python之父”。
近期以来,Python甚至已经超过C语言而位列排行榜的榜首,成为最流行的计算机编程语言。
Python作为一门开源、免费的编程语言,任何人都可以使用和修改。Python的官方网站为:https://www.python.org/ 它提供了有关Python最权威的信息,并提供了Python安装包的下载,目前Python最新的稳定版本是3.10.3。
尽管Python内置的集成开发环境已具备了很强的功能,但对于大型的开发它还是略显欠缺。为了弥补这种不足,可安装功能更丰富的第三方集成开发环境。
1)PyTorch
PyTorch是基于Python编程语言的以张量运算以及自动梯度为核心功能的一个开源的Python第三方库。
PyTorch的官网为:https://pytorch.org/,提供了详细的安装指导以供使用。
2)Visdom
Visdom是一款 Facebook 开源的用于创建、组织和共享数据的可视化工具,它支持Python编程语言,使用起来十分方便。该工具可以生成散点图、拆线图、柱状图,3D视图等多种类型的图形和图像,功能强大,显示效果出众。
Visdom能实时更新图像处理的结果和深度学习模型训练进度,是一款优秀的数据可视化的工具。
图4 绘制功能类型
3)Spyder
Spyder自身是一个Python的第三方库,因此Spyder的安装十分简单,直接使用Python第三方库的安装方法。
Spyder界面如图5所示,它菜单栏和工具栏,下方的状态栏,主窗体等部分。在IPython动态交互环境窗口,可以即时编写代码和查看运行结果。
图5 软件界面
这样强大的PyThon值得好好学习并掌握,当然对第三方软件也是不能放过呦!
- 2024-11-23
-
发表了主题帖:
【翌创ET6001测评】点阵板显示驱动
在通常的情况下,我们所用的显示器件多为数码管、液晶屏等。但在公共场合,则需要使用较大尺寸和规格的显示器件。
市场上的告广牌多是由半板拼接而成的,这里就选用一款P4.75的红色点阵板,其显示分辨率为16*64像素点,其外观如图1所示。
在通常的情况下,我们所用的显示器件多为数码管、液晶屏等。但在公共场合,则需要使用较大尺寸和规格的显示器件。
市场上的告广牌多是由半板拼接而成的,这里就选用一款P4.75的红色点阵板,其显示分辨率为16*64像素点,其外观如图1所示。
图1 点阵屏外观
该点阵板随使用的接口方式为HUB08,其各引脚的名称如图2所示。
图2 HUB08接口
点阵板与开发板的引脚连接关系为:
A ---- P24
B ---- P11
C ---- P12
D ----P13
R1 ---- P23
CLK----P22
EN ---- P21
STB---- P25
所用引脚的工作模式配置函数为:
static void dzp_CONFIG(void)
{
IOC_Init_TypeDef init;
IOC_ConfigStructInit(&init);
init.mode = IOC_AF_MODE_3;
init.dir = GPIO_DIR_OUT;
init.pull = IOC_PULL_NONE;
IOC_Config(IOC_PIN_GPIO_PLL_REF, &init);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_01);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_02);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_03);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_04);
GPIO_PortOutputEnable(GPIO2, GPIO_PIN_05);
GPIO_PortOutputEnable(GPIO1, GPIO_PIN_01);
GPIO_PortOutputEnable(GPIO1, GPIO_PIN_02);
GPIO_PortOutputEnable(GPIO1, GPIO_PIN_03);
}
所用引脚输出高低电平的语句定义为:
#define LR1_high GPIO_WritePin(GPIO2, GPIO_PIN_03, SET)
#define LR1_low GPIO_WritePin(GPIO2, GPIO_PIN_03, RESET)
#define CLK_high GPIO_WritePin(GPIO2, GPIO_PIN_02, SET)
#define CLK_low GPIO_WritePin(GPIO2, GPIO_PIN_02, RESET)
#define LSTB_high GPIO_WritePin(GPIO2, GPIO_PIN_05, SET)
#define LSTB_low GPIO_WritePin(GPIO2, GPIO_PIN_05, RESET)
#define LEN_high GPIO_WritePin(GPIO2, GPIO_PIN_01, SET)
#define LEN_low GPIO_WritePin(GPIO2, GPIO_PIN_01, RESET)
#define LA_high GPIO_WritePin(GPIO2, GPIO_PIN_04, SET)
#define LA_low GPIO_WritePin(GPIO2, GPIO_PIN_04, RESET)
#define LB_high GPIO_WritePin(GPIO1, GPIO_PIN_01, SET)
#define LB_low GPIO_WritePin(GPIO1, GPIO_PIN_01, RESET)
#define LC_high GPIO_WritePin(GPIO1, GPIO_PIN_02, SET)
#define LC_low GPIO_WritePin(GPIO1, GPIO_PIN_02, RESET)
#define LD_high GPIO_WritePin(GPIO1, GPIO_PIN_03, SET)
#define LD_low GPIO_WritePin(GPIO1, GPIO_PIN_03, RESET)
点阵板发送数据的函数为:
static void OutByte(uint16_t dat)
{
uint8_t i=0 ;
for(i=0;i<16;i++)
{
CLK_low;
if(dat&0x0001)
{
LR1_high;
}
else
{
LR1_low;
}
dat=dat>>1;
CLK_high;
}
}
发送多列数据的函数为:
static void DisCol(uint16_t lenght)
{
uint16_t dat;
uint8_t m=0;
while(lenght--)
{
dat=(S[sj[m+1]*16+ScanRow]<<8)+S[sj[m]*16+ScanRow];
OutByte(dat);
m=m+2;
}
}
输出行地址的函数为:
static void SeleRow(uint8_t Nd)
{
uint8_t N;
N=Nd;
N=N%16;
if(N&0x01) LA_high;
else LA_low;
if (N&0x02) LB_high;
else LB_low;
if (N&0x04) LC_high;
else LC_low;
if (N&0x08) LD_high;
else LD_low;
}
实现显示输出的函数为:
static void Display(void)
{
DisCol(4);
LEN_high;
LSTB_high;
LSTB_low;
SeleRow(ScanRow);
LEN_low;
ScanRow++;
if(ScanRow>15) ScanRow=0;
}
模拟RTC计时效果的显示函数为:
static void ShowTime(void)
{
sj[0]= 1;
sj[1]= 2;
sj[2]= 10;
sj[3]= 3;
sj[4]= 0;
sj[5]= 10;
sj[6]= 0;
sj[7]= 8;
Display();
}
为进行显示,所配置的字模由数组来存储,其内容为:
uint8_t S[]={
0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00,/*"0",0*/
0x00,0x00,0x00,0x08,0x0E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00,/*"1",1*/
0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x20,0x20,0x10,0x08,0x04,0x42,0x7E,0x00,0x00,/*"2",2*/
0x00,0x00,0x00,0x3C,0x42,0x42,0x20,0x18,0x20,0x40,0x40,0x42,0x22,0x1C,0x00,0x00,/*"3",3*/
0x00,0x00,0x00,0x20,0x30,0x28,0x24,0x24,0x22,0x22,0x7E,0x20,0x20,0x78,0x00,0x00,/*"4",4*/
0x00,0x00,0x00,0x7E,0x02,0x02,0x02,0x1A,0x26,0x40,0x40,0x42,0x22,0x1C,0x00,0x00,/*"5",5*/
0x00,0x00,0x00,0x38,0x24,0x02,0x02,0x1A,0x26,0x42,0x42,0x42,0x24,0x18,0x00,0x00,/*"6",6*/
0x00,0x00,0x00,0x7E,0x22,0x22,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,/*"7",7*/
0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00,/*"8",8*/
0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x64,0x58,0x40,0x40,0x24,0x1C,0x00,0x00,/*"9",9*/
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,/*":",10*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"-",11*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
实现显示输出的主程序为:
int32_t main(void)
{
dzp_CONFIG();
ScanRow=0;
while (1)
{
ShowTime();
}
}
经程序的编译与运行,其执行效果如图3所示。
图3 硬件连接及显示效果
-
加入了学习《发帖插入视频1》,观看 动画插件效果
-
加入了学习《发帖插入视频1》,观看 五角星绘制
-
回复了主题帖:
《计算机视觉之PyTorch数字图像处理》----初品之感受
chejm 发表于 2024-11-23 18:10
看了楼主分享的资料介绍,对这本书的兴趣大增,希望有时间能认真学习一下这本书
感谢支持!!!
-
发表了主题帖:
《计算机视觉之PyTorch数字图像处理》----初品之感受
《计算机视觉之PyTorch数字图像处理》这本书是由侯伟来编写,该书共分三篇11章,它以我们司空见惯而又习以为常的视觉问题为切入点,从而展开丰富的知识讲解。
之所以视觉的问题习以为常是因为我们每天都利用它来观察世界,似乎它没有啥研究的必要,我们天生就具备这样的能力。即使身上这个光学器件出现问题,那也是去医院找医生来解决问题,当然这只是开个玩笑。
其实,对视觉的研究过程是较为漫长的,那人类是怎样开始这方面的研究呢?
这还要从人类发现光以直线传播开始,继而观察到了小孔成像的现象,并通过描绘影像来记录景观。
随后,是化学知识的提高,尤其是感光材料的出现,才开始以胶片来记录景观。
受感光材料的限制,最初的照片是反应灰度层次的图像,后来是三色感光材料的出现,才促使彩色照片的出现。至此,人类还仍处于真实记录自然景观的阶段。
后来是计算机及电荷耦合器件CCD的出现,才是图像处理技术萌发起来。这是源于光学器件只是一种图像采集器件,要在显示器件上再现原图像,还需计算机对采集信号的离散化处理并存储在存储单元中。再经显示器件将数据呈现到显示屏上的图像。也正是基于它,才有了数字图像的概念。随后,为例保存和传递数字图像,又推出图像文件格式的产生,如bmp、jpg、gif等文件格式。
对于一幅图像来讲,其分辨率越高,其图像越清晰,相应的其所含的像素也越多,并导致其所占用的存储空间越多。为此就出现了无损和有损压缩技术,如bmp文件就采用无损压缩,jpg文件则属于有损压缩。
那是使用无损压缩好还是使用压缩压缩好呢?
其实这要看使用的场合,利用要用单片机来显示图像,就以使用无损压缩的bmp文件为好,因为它无需对数据做进一步的数据处理。而对于ARM来讲,它要显示图像则可以使用有损压缩格式的jpg文件,因为它具有数据解压缩能力。
对于gif格式文件来讲,它也是具有自身特点的,即它可以将多帧图像存放到一起,从而显示具有动画效果的画面。
其实大家通常所说的“图像处理”是指数字图像处理。而图像处理也是分层次的,通常在各类院校中,是将讲授photoshop这类课程称之为图像处理,其实这是很狭隘的。因为它只是面向解决图像显示效果方面的处理,即使用滤镜这一特效工具来制作各种效果,其实质只是一种艺术效果处理。而图像处理的本质则是进行图像数据的分析处理和深度发掘,如将采集的可视范围外的信号通过变换处理,转化可视化的图像的X光透视,又如将各地采集的温度数据经平滑处理而绘制出的区域气象温度图等。可见图像处理的内容是非常丰富的,所涉及的领域也十分广泛。
图1 X光透视
图2 气象温度图
随着人工智能技术的出现,图像处理又迈向了一个新的高度,那就是对图像数据的深度发掘和利用,例如从图像中寻找和识别文字信息、对车牌进行识别及相应的管控、对图片中的物体或器件进行识别和数量统计、对图像中的人进行识别及使用等,甚至可以进行人脸识别、手语姿态识别等。
此外,通过多视角的拍摄可以进行物体的三位实体构建并加以应用。、
总之,图像处理技术,已全面走入人们的生活,并向我们展现出更加深远的探索空间,并引导我们前行。
- 2024-11-17
-
发表了主题帖:
【翌创ET6001测评】W25X读写测试
翌创ET6001开发板提供了对NorFlash存储器件的读写功能,所支持的芯片为W25X40。
由资料可知,W25X40是一款4M的flash,其工作电压为2.7-3.6V,存储容量4M-bit。具有双向SPI输出功能,是普通SPI接口的2倍速度。
该芯片与开发板的连接关系为:
CLK---GPIO2_0
MISO---GPIO2_1
MOSI---GPIO2_2
CS----GPIO2_3
由于在开发板上并没有配置该芯片,故在完成程序编译和运行的情况下,其运行结果如图1所示。
图1 无芯片测试
由此可知,测试程序的基本功能为:
读取芯片ID
擦除芯片
写入数据
读取数据
手头有一款W25Q16的存储模块,由资料可知W25Q16是一款16M-bit的存储芯片,工作电压为2.7V到3.6V,正常工作时电流小于5mA。
W25Q16的每一页有256个字节,共有8192页,每16页是一个扇区。每页的256个字节用一次页编程指令接口完成。每次擦除128页(32KB块)或全片擦除。
这里用该存储模块来进行读写测试,相应的引脚连接关系为:
CLK---GPIO2_0
DO ---GPIO2_1
DI---GPIO2_2
CS----GPIO2_3
读取芯片ID的函数为:
static void SPI_ReadDeviceID(void)
{
uint8_t sendData[20] = {0};
uint8_t receiveData[20] = {0};
SPI_InitType init;
SPI_DeInit(SPI0);
SPI_StructInit(&init);
init.dataFrameSize = 0x7;
init.transferMode = SPI_EEPROM_READ;
init.clkDiv = 2;
init.rxSampleDly = 2;
init.readDataNum = 2;
SPI_Init(SPI0, &init);
SPI_Enable(SPI0);
sendData[0] = FLASHCMD_READ_DEVICE_ID;
sendData[1] = 0x0;
sendData[2] = 0x0;
sendData[3] = 0x0;
SPI_Transmit(SPI0, (uint8_t *)(&sendData), 4, MAX_TIMEOUT);
SPI_Receive(SPI0, receiveData, 2, MAX_TIMEOUT);
printf("read w25x40 device identification [0x%x,0x%x]\n", receiveData[0], receiveData[1]);
}
进行芯片整体擦除的函数为:
static void SPI_DeviceChipErase(void)
{
SPI_DeviceWriteEnable();
uint8_t sendData;
sendData = FLASHCMD_CHIP_ERASE;
SPI_Transmit(SPI0, (uint8_t *)(&sendData), 1, MAX_TIMEOUT);
while (!SPI_IsDeviceReady());
}
读取数据的函数为:
static void SPI_DeviceRead(void)
{
uint32_t i;
uint32_t addr = 0;
uint8_t data[4] = {0};
uint8_t sendData[4] = {0};
while(SPI_STATE_READY != SPI_GetState(SPI0));
while (!SPI_IsDeviceReady());
while(SPI_STATE_READY != SPI_GetState(SPI0));
SPI_ConfigTransMode(SPI0, SPI_EEPROM_READ);
SPI_ConfigFrameNum(SPI0, 4);
sendData[0] = FLASHCMD_READ_DATA;
sendData[1] = (addr & 0xFF0000) >> 16;
sendData[2] = (addr & 0xFF00) >> 8;
sendData[3] = addr & 0xFF;
SPI_Transmit(SPI0, (uint8_t *)(&sendData), 4, MAX_TIMEOUT);
SPI_Receive(SPI0, data, 4, MAX_TIMEOUT);
for (i = 0;i < 4;i++) {
printf("read data = 0x%x\n",data[i]);
}
}
写入数据的函数为:
static void SPI_DeviceWrite(void)
{
bool state;
uint32_t addr = 0x0;
uint8_t data[8] = {0};
state = SPI_DeviceWriteEnable();
if (state == false)
return ;
data[0] = FLASHCMD_PAGE_PROGRAM;
while(SPI_STATE_READY != SPI_GetState(SPI0));
data[1] = (uint8_t)((addr & 0xFF0000) >> 16);
data[2] = (uint8_t)((addr & 0xFF00) >> 8);
data[3] = (uint8_t)(addr & 0xFF);
data[4] = 0x12;
data[5] = 0x34;
data[6] = 0x56;
data[7] = 0x78;
SPI_Transmit(SPI0, data, 8, MAX_TIMEOUT);
while(SPI_STATE_READY != SPI_GetState(SPI0));
while (!SPI_IsDeviceReady());
printf("write data 0x12,0x34,0x56,0x78\n");
}
需注意的是,无论是读取函数还是是写入函数,其操作地址都是在函数内通过变量addr来指定的,这样就不如以参数的方式来指定地址更为方便。
在连接后,其工作状态如图2及运行结果见图3所示,说明尽管所提供的例程是为W25X40所准备的,但对于W25Q16来说依然有效。
图2 运行状态
图3 运行结果
有了W25Q16存储模块的支持,就可为开发板提供更大的数据存储空间以放置常用的相对固定数据,如字库和图片库等,作用还是很强的。
-
回复了主题帖:
【翌创ET6001测评】LCD屏显示驱动
Jacktang 发表于 2024-11-16 09:11
期待后续与A/D数据采集功能相结合来实现温度检测功能。
时间允许的情况下,整一个。
- 2024-11-15
-
回复了主题帖:
共读入围:《计算机视觉之PyTorch数字图像处理》
个人信息无误,确认可以完成评测计划。