模块[camera]_LED-白平衡

本文详细介绍了白平衡的概念及其在摄像领域的重要作用,包括白平衡的工作原理、如何进行白平衡调整等关键信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



转自:http://blog.sina.com.cn/s/blog_771419e70100pw4m.html

白平衡是电视摄像领域一个非常重要的概念,通过它可以解决色彩还原和色调处理的一系列问题。白平衡是随着电子影像再现色彩真实而产生的,在专业摄像领域白平衡应用的较早,现在家用电子产品(家用摄像机、数码照相机)中也广泛地使用,虽然技术的发展使得白平衡调整变得越来越简单容易,但许多使用者还不甚了解白平衡的工作原理,理解上存在诸多误区

    一、 什么是白平衡
    白平衡,字面上的理解是白色的平衡。那什么是白色?这就涉及到一些色彩学的知识,白色是指反射到人眼中的光线由于蓝、绿、红三种色光比例相同且具有一定的亮度所形成的视觉反应。我们都知道白色光是由赤、橙、黄、绿、青、蓝、紫七种色光组成的,而这七种色光又是有红、绿、蓝三原色按不同比例混合形成,当一种光线中的三原色成分比例相同的时候,习惯上人们称之为消色,黑、白、灰、金和银所反射的光都是消色。通俗的理解白色是不含有色彩成份的亮度。人眼所见到的白色或其他颜色同物体本身的固有色、光源的色温、物体的反射或透射特性、人眼的视觉感应等诸多因素有关(请参阅《色彩学原理》),举个简单的例子,当有色光照射到消色物体时,物体反射光颜色与入射光颜色相同,既红光照射下白色物体呈红色,两种以上有色光同时照射到消色物体上时,物体颜色呈加色法效应,如红光和绿光同时照射白色物体,该物体就呈黄色。当有色光照射到有色物体上时,物体的颜色呈减色法效应。如黄色物体在品红光照射下呈现红色,在青色光照射下呈现绿色,在蓝色光照射下呈现灰色或黑色。
    在了解白平衡之前还要搞清另一个一个非常重要的概念――色温。所谓色温,简而言之,就是定量地以开尔文温度(K)来表示色彩。英国著名物理学家开尔文认为,假定某一黑体物质,能够将落在其上的所有热量吸收,而没有损失,同时又能够将热量生成的能量全部以“光”的形式释放出来的话,它便会因受到热力的高低而变成不同的颜色。例如,当黑体受到的热力相当于500—550摄氏度时,就会变成暗红色,达到1050-1150摄氏度时,就变成黄色,温度继续升高会呈现蓝色。光源的颜色成分是与该黑体所受的热力温度是相对应的,任何光线的色温是相当于上述黑体散发出同样颜色时所受到的“温度”,这个温度就用来表示某种色光的特性以区别其它,这就是色温。打铁过程中,黑色的铁在炉温中逐渐变成红色,这便是黑体理论的最好例子。色温现象在日常生活中非常普遍,相信人们对它并不陌生。钨丝灯所发出的光由于色温较低表现为黄色调,不同的路灯也会发出不同颜色的光,天然气的火焰是蓝色的,原因是色温较高。万里无云的蓝天的色温约为10000 K,阴天约为7000~9000 K,晴天日光直射下的色温约为6000 K,日出或日落时的色温约为2000 K,烛光的色温约为1000 K。这时我们不难发现一个规律:色温越高,光色越偏蓝;色温越低则偏红。某一种色光比其它色光的色温高时,说明该色光比其它色光偏蓝,反之则偏红;同样,当一种色光比其它色光偏蓝时说明该色光的色温偏高,反之偏低。
    由于人眼具有独特的适应性,使我们有的时候不能发现色温的变化。比如在钨丝灯下呆久了,并不会觉得钨丝灯下的白纸偏红,如果突然把日光灯改为钨丝灯照明,就会觉查到白纸的颜色偏红了,但这种感觉也只能够持续一会儿。摄像机的CCD并不能像人眼那样具有适应性,所以如果摄像机的色彩调整同景物照明的色温不一致就会发生偏色。那么什么是白平衡呢?白平衡就是针对不同色温条件下,通过调整摄像机内部的色彩电路使拍摄出来的影像抵消偏色,更接近人眼的视觉习惯。白平衡可以简单地理解为在任意色温条件下,摄像机镜头所拍摄的标准白色经过电路的调整,使之成像后仍然为白色。这是一种经常出现的情况,但不是全部,白平衡其实是通过摄像机内部的电路调整(改变蓝、绿、红三个CCD电平的平衡关系)使反射到镜头里的光线都呈现为消色。如果以偏红的色光来调整白平衡,那么该色光的影像就为消色,而其他色彩的景物就会偏蓝(补色关系)。
    二、 白平衡的工作原理
    白平衡是一个很抽象的概念,最通俗的理解就是让白色所成的像依然为白色,如果白是白,那其他景物的影像就会接近人眼的色彩视觉习惯。调整白平衡的过程叫做白平衡调整,白平衡调整在前期设备上一般有三种方式:预置白平衡、手动白平衡调整和自动跟踪白平衡调整。通常按照白平衡调整的程序,推动白平衡的调整开关,白平衡调整电路开始工作,自动完成调校工作,并记录调校结果。如果掌握了白平衡的工作原理,那么使用起来会更加有的放矢,得心应手。
    白平衡是这样工作的:摄像机内部有三个CCD电子耦合元件,他们分别感受蓝色、绿色、红色的光线,在预置情况下这三个感光电路电子放大比例是相同的,为1:1:1的关系,白平衡的调整就是根据被调校的景物改变了这种比例关系。比如被调校景物的蓝、绿、红色光的比例关系是2:1:1(蓝光比例多,色温偏高),那末白平衡调整后的比例关系为1:2:2,调整后的电路放大比例中明显蓝的比例减少,增加了绿和红的比例,这样被调校景物通过白平衡调整电路到所拍摄的影像,蓝、绿、红的比例才会相同。也就是说如果被调校的白色偏一点蓝,那么白平衡调整就改变正常的比例关系减弱蓝电路的放大,同时增加绿和红的比例,使所成影像依然为白色。
    换一个思路来考虑白平衡调整的问题,摄像机在白平衡调整容度之内不会“拒绝”放在镜头前面的被调校景物,就是说镜头可以对着任何景物来调整白平衡。大多情况下使用白色的调白板(卡)来调整白平衡,是因为白色调白板(卡)可最有效地反映环境的色温,其实很多时候某种环境下白板(卡)并不是白色,多多少少会偏一点蓝或其它的颜色,经验丰富的摄像也会利用蓝天来调白平衡,从而得到偏红黄色调的画面。搞清楚白平衡的工作原理之后,再使用的时候就会大胆地尝试不同的效果,丰富了摄像创作。
    三、白平衡调整
    在生活中日光的色温是不断变化的,可以说没有两个地方的色温会完全一样,不同的地域、季节、地面环境、天气、早晚等等都会对色温造成影响,还有大量的人工光源,色温也不尽相同。摄像师调整白平衡的方法大体分粗调、精细调整和自动跟踪(ATW)三种:粗调指在预置情况下改变色温滤光片,使色温接近到到3200K的出厂设置;精细调整是指在色温滤光片的配合下通过摄像机白平衡调整功能,针对特定环境色温得到一个更为精确的调整结果;自动跟踪是指依靠摄像机的自动跟踪功能(ATW),摄像机自身根据画面的色温变化随时调整。
    预置功能是摄像机以3200K色温条件下设置的蓝、绿、红感光平衡。当环境色温为3200K时,摄像机色温滤光片放置在3200K,景物可以得到正确的色彩还原;当环境色温为5600K时,摄像机色温滤光片放置在5600K,景物可以得到正确的色彩还原。当环境色温在3200K上下1000K和5600K上下1000K范围内,利用白平衡预置功能可以得到人眼可以接受的色彩还原,由于色温偏差不大,使拍摄出的画面呈现出细微的色彩变化。这有一个好处,不同的生活环境本身会由于环境色和照明差异的影响而色彩基调不同,如果到处调白会使不同的环境呈现单一白光照明的效果,而利用白平衡预置则可以保留这种丰富的色彩变化。
    一般精细调白的方法是,在拍摄环境中以顺着拍摄方向的调白板(卡)来调整白平衡。这是一种普遍的情况,还有几种非常灵活的精细调白方法。利用一块透过性良好的标准白板,把它置于紧贴镜头的前面,在拍摄环境中对着光源照明方向或对着主拍摄方向来调整白平衡,专业的摄像机会给出一个色温读数,比如是5000K,如果希望拍摄还原正常的画面就以这个白平衡结果来拍摄。在摄像创作中,有时希望得到色彩偏差的画面来达到创作目的,这时可以利用任何景物来调整白平衡,被调白景物的色温同画面的色彩偏差呈补色关系,既以红色调白画面偏向青色,以绿色调白画面偏向品色,以兰色调白画面偏向黄色。白平衡自动跟踪功能(ATW)是随着镜头摄取景物的色温变化而时实调整,如果一个推镜头或摇镜头由于被摄景物的色温(镜头摄入景物的色温同环境照明色温是不同的)变化,会使画面在一个镜头内发生色彩变化。如镜头由人物全景推近脸部特写,因为景别的变化摄入镜头的色温会不同,画面中人物的肤色也就会发生变化,所以非特殊情况不建议使用该模式。
02-23 16:07:03.866 INFO ==========> LedSnapshotTest <========== 02-23 16:07:13.222 INFO [Test] test_led_snapshot 02-23 16:07:49.331 ERROR Exception occurred in test_led_snapshot. Traceback (most recent call last): File “/home/its/anaconda3/lib/python3.12/site-packages/mobly/base_test.py”, line 818, in exec_one_test test_method() File “/home/its/0.ITS/15R2/android-cts15-r2-verifier/android-cts-verifier/CameraITS/tests/scene_flash/test_led_snapshot.py”, line 264, in test_led_snapshot raise AssertionError(‘\n’.join(failure_messages)) AssertionError: R/G ratio: 3.163611974354118 not within the limits. Format: yuv, Size: 640x480 B/G ratio: 3.163611974354118 not within the limits. Format: yuv, Size: 640x480 Flash image mean not within limits for channel R. Format: yuv,Size: 640x480 Flash image mean not within limits for channel G. Format: yuv,Size: 640x480 Flash image mean not within limits for channel B. Format: yuv,Size: 640x480 R/G ratio: 3.317438224350318 not within the limits. Format: yuv, Size: 256x144 B/G ratio: 3.317438224350318 not within the limits. Format: yuv, Size: 256x144 Flash image mean not within limits for channel R. Format: yuv,Size: 256x144 Flash image mean not within limits for channel G. Format: yuv,Size: 256x144 Flash image mean not within limits for channel B. Format: yuv,Size: 256x144 02-23 16:07:49.332 INFO [Test] test_led_snapshot FAIL 02-23 16:07:49.352 INFO Summary for test class LedSnapshotTest: Error 0, Executed 1, Failed 1, Passed 0, Requested 1, Skipped 0 02-23 16:07:49.352 INFO Summary for test run TEST_BED_SENSOR_FUSION@02-23-2025_16-07-03-865: Total time elapsed 45.48659456789028s Artifacts are saved in “/tmp/CameraITS_99tftggi/cam_id_0/scene_flash/TEST_BED_SENSOR_FUSION/02-23-2025_16-07-03-865” Test summary saved in “/tmp/CameraITS_99tftggi/cam_id_0/scene_flash/TEST_BED_SENSOR_FUSION/02-23-2025_16-07-03-865/test_summary.yaml” Test results: Error 0, Executed 1, Failed 1, Passed 0, Requested 1, Skipped 0这个测试项报错,有修改方式吗
03-15
#__________________________________________________________________ # 导入模块 import sensor, time, image # 导入感光元件模块 sensor 跟踪运行时间模块 time 机器视觉模块 image import utime # 导入延时模块 utime from fpioa_manager import fm # 从 fpioa_manager 模块中导入 引脚注册模块 fm from Maix import GPIO # 从 Maix 模块中导入 模块 GPIO import lcd # 导入 LCD 模块 from machine import Timer, PWM, UART # 从 machine 模块中导入 定时器模块 Timer 脉宽调制模块 PWM 双向串行通信模块 UART import math # 导入数学函数模块 math #__________________________________________________________________ # 感光元件设置 sensor.reset() # 重置并初始化感光元件 默认设置为 摄像头频率 24M 不开启双缓冲模式 #sensor.reset(freq=24000000, dual_buff=True) # 设置摄像头频率 24M 开启双缓冲模式 会提高帧率 但内存占用增加 sensor.set_pixformat(sensor.RGB565) # 设置图像格式为 RGB565 (彩色) 除此之外 还可设置格式为 GRAYSCALE 或者 YUV422 sensor.set_framesize(sensor.QVGA) # 设置图像大小为 QVGA (320 x 240) 像素个数 76800 K210最大支持格式为 VGA sensor.set_auto_exposure(0) # 关闭自动曝光 #sensor.set_auto_exposure(0, exposure=120000) # 设置手动曝光 曝光时间 120000 us sensor.set_auto_gain(0) # 关闭画面增益 sensor.set_auto_whitebal(0) # 关闭RGB自动增益(白平衡) #sensor.set_auto_gain(0, gain_db = 12) # 设置画面增益 17 dB 影响实时画面亮度 #sensor.set_auto_whitebal(0, rgb_gain_db = (0,0,0)) # 设置RGB增益 0 0 0 dB 影响画面色彩呈现效果 在 K210 上无法调节增益 初步判定是感光元件 ov2640 无法支持 #sensor.set_contrast(0) # 设置对比度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释 #sensor.set_brightness(0) # 设置亮度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释 #sensor.set_saturation(0) # 设置饱和度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释 #sensor.set_vflip(1) # 打开垂直翻转 如果是 01Studio 的 K210 不开启会导致画面方向与运动方向相反 sensor.set_hmirror(1) # 打开水平镜像 如果是 01Studio 的 K210 不开启会导致画面方向与运动方向相反 sensor.skip_frames(time = 8000) # 延时跳过8s 等待感光元件稳定 #__________________________________________________________________ # 创建时钟对象 clock = time.clock() # 创建时钟对象 clock #__________________________________________________________________ # 定时器的使用 # 定义定时器属性类 class Timer_Property(): cnt = 0 # 定时器计数值 cnt_max = 0 # 定时器计数值上限 period = 0 # 定时器周期 freq = 0 # 定时器频率 # 定时器0 配置_______________________________________________________ # 定时器0 实例化类 timer0 = Timer_Property() # 实例化定时器属性类 Timer_Property() 为 timer0 timer0.cnt_max = 9 # 设定 定时器0 的计数值上限为 9 timer0.period = 100 # 设定 定时器0 的周期为 100 # 定时器0 定义回调函数 def Timer0_Back(tim0): if timer0.cnt < timer0.cnt_max: # 若 定时器0 的计数值小于 定时器0 的计数值上限 timer0.cnt = timer0.cnt + 1 # 计数值自增 else: timer0.cnt = 0 # 超出计数值上限 则计数值重置为0 # 定时器0 初始化 tim0 = Timer(Timer.TIMER0, # 定时器编号 定时器0 Timer.CHANNEL0, # 定时器通道 通道0 mode = Timer.MODE_PERIODIC, # 定时器模式 周期性 unit = Timer.UNIT_MS, # 定时器周期单位 ms period = timer0.period, # 定时器周期 timer0.period 若 unit 为 Timer.UNIT_MS 则周期为 timer0.period ms callback = Timer0_Back) # 定时器触发中断后执行的回调函数 Timer0_Back #__________________________________________________________________ # 串口的使用 # 串口1 设置 P9 RX P6 TX #fm.register(9, fm.fpioa.UART1_RX, force = True) # 配置 9 脚为 UART1_RX 强制注册 #fm.register(6, fm.fpioa.UART1_TX, force = True) # 配置 6 脚为 UART1_TX 强制注册 uart1 = UART(UART.UART1, 115200, 8, 0, 1) # 设置 uart1 为 串口1 波特率 921600 数据位 8位 校验位 0位 停止位 1位 # 串口2 设置 P7 RX P8 TX fm.register(9, fm.fpioa.UART2_RX, force = True) # 配置 7 脚为 UART2_RX 强制注册 fm.register(6, fm.fpioa.UART2_TX, force = True) # 配置 8 脚为 UART2_TX 强制注册 uart2 = UART(UART.UART2, 921600, 8, 0, 1) # 设置 uart2 为 串口2 波特率 921600 数据位 8位 校验位 0位 停止位 1位 #__________________________________________________________________ # 串口发送 # 定义 UART 发送类 class UART_Transmit(): # 定义 UART 发送类 pack_flag = 0 # 打包方法标志位 head1 = 0x00 # uint8_t 帧头1 head2 = 0x00 # uint8_t 帧头2 x = 0 # uint16_t 目标x轴坐标 y = 0 # uint16_t 目标y轴坐标 color = 0 # uint8_t 目标颜色标志位 shape = 0 # uint8_t 目标形状标志位 flag = 0 # uint8_t 目标标志位 mode = 0 # uint8_t 模式标志位 # 实例化类 fasong = UART_Transmit() # 实例化 UART_Transmit() 为 fasong fasong.pack_flag = 1 # 打包方法为 方法1 fasong.head1 = 0xAA # fasong 的帧头1为 0xAA fasong.head2 = 0xAA # fasong 的帧头2为 0xAA jieshou = UART_Transmit() # 实例化 UART_Transmit() 为 jieshou jieshou.pack_flag = 2 # 打包方法为 方法2 jieshou.head1 = 0xAA # jieshou 的帧头1为 0xAA jieshou.head2 = 0xAA # jieshou 的帧头2为 0xAA # 定义打包函数 def Pack_Data(TData): data = UART_Pack_Method(TData) # 根据不同的方法打包发送数据 # 数据包的长度 data_len = len(data) # 获得数据包总长度 data[2] = data_len - 4 # 有效数据的长度 扣去 帧头1 帧头2 有效数据长度位 校验位 # 校验和 sum = 0 # 和置零 for i in range(0,data_len-1): sum = sum + data[i] # 和累加 data[data_len-1] = sum # 和赋值 给数组最后一位发送 只保存低8位 溢出部分无效 # 返回打包好的数据 return data #__________________________________________________________________ # 串口接收 # 定义 UART 接收类 class UART_Receive(object): # 定义 UART 接收类 uart_buf = [] # 串口缓冲区数组 data_len = 0 # 有效数据长度 data_cnt = 0 # 总数据长度 state = 0 # 接收状态 buf_len = 0 # 保存串口等待字节的数量 head1 = 0x00 # 接收帧头1 head2 = 0x00 # 接收帧头2 lenmax = 0 # 有效数据最大长度 save_flag = 0 # 保存方法标志位 # 实例化类 rfasong = UART_Receive() # 实例化 UART_Receive() 为 rfasong rfasong.head1 = 0xAA # rfasong 的帧头1为 0xAA rfasong.head2 = 0xAA # rfasong 的帧头2为 0xAA rfasong.lenmax = 40 # rfasong 的有效数据最大长度为 40 rfasong.save_flag = 1 # rfasong 的保存方法标志位为 1 rjieshou = UART_Receive() # 实例化 UART_Receive() 为 rjieshou rjieshou.head1 = 0xAA # rjieshou 的帧头1为 0xAA rjieshou.head2 = 0xAA # rjieshou 的帧头2为 0xAA rjieshou.lenmax = 40 # rjieshou 的有效数据最大长度为 40 rjieshou.save_flag = 2 # rjieshou 的保存方法标志位为 2 # 定义串口数据读取函数 def UART_Read(RData, uart): RData.buf_len = uart.any() # 检查 串口 是否有内容需要读取 返回等待的字节数量(可能为0) for i in range(0, RData.buf_len): # 读取 RData.buf_len 个数据 Receive_Data(RData, uart.readchar()) # 接收单个数据 uart.readchar() 然后将这个数据传递到函数 Receive_Data() 进行 数据接收 # 定义串口数据接收函数 def Receive_Data(RData, buf): if RData.state == 0 and buf == RData.head1: # 判断帧头1是否符合要求 符合则进入下一个状态 RData.state = 1 # 更改状态为 1 RData.uart_buf.append(buf) # 将这个数据添加到数组末尾 elif RData.state == 1 and buf == RData.head2: # 判断帧头2是否符合要求 符合则进入下一个状态 RData.state = 2 # 更改状态为 2 RData.uart_buf.append(buf) # 将这个数据添加到数组末尾 elif RData.state == 2 and buf < RData.lenmax: # 有效数据长度位 规定有效数据长度小于40 符合则进入下一个状态 RData.state = 3 # 更改状态为 3 RData.data_len = buf # 获得有效数据长度 RData.data_cnt = buf + 4 # 获得总数据长度 总数据长度 = 帧头1 + 帧头2 + 有效数据长度位 + 有效数据 + 校验位 RData.uart_buf.append(buf) # 将这个数据添加到数组末尾 elif RData.state == 3 and RData.data_len > 0: # 存储有效数据长度个数据 RData.data_len = RData.data_len - 1 # 每存储一次 还需要存储的数据个数减1 RData.uart_buf.append(buf) # 将这个数据添加到数组末尾 if RData.data_len == 0: # 直到存储完毕 RData.state = 4 # 进入下一个状态 elif RData.state == 4: # 当接收到存储完毕的信息 RData.uart_buf.append(buf) # 保存最后一位校验位 将这个数据添加到数组末尾 RData.state = 0 # 状态重置为0 调用串口数据解析函数进行数据解析 Parse_Data(RData) # 解析数据 #print(RData.uart_buf) # 打印接收数组 若接收结果不对 可取消注释查看数组 RData.uart_buf = [] # 清空缓冲区 准备下次接收数据 else: # 不满足以上条件 视为接收出错 重置状态为0 丢弃所有数据 准备下一次接收数据 RData.state = 0 # 重置状态为0 RData.uart_buf = [] # 清空缓冲区 准备下一次接收数据 # 定义串口数据解析函数 def Parse_Data(PData): # 和累加 sum = 0 # 和置0 i = 0 # 已循环次数置0 while i < (PData.data_cnt - 1): # 循环累加 sum = sum + PData.uart_buf[i] # 累加求数组和 i = i + 1 # 已循环次数自增 # 求余 因为 校验和 为 8 位 超出部分无效 因此只校验 低8位 即可 sum = sum % 256 # 和对256取余 得低八位 # 和校验失败则退出 if sum != PData.uart_buf[PData.data_cnt - 1]: # 和取余结果若不等于校验位的值 return # 退出 # 和校验成功则根据保存方法的不同 接收数据 UART_Save_Method(PData) #__________________________________________________________________ # 调试区 # 定义 K210 属性类 class K210_Property(object): # 定义 K210 接收类 x = 0 # uint16_t 目标x轴坐标 y = 0 # uint16_t 目标y轴坐标 color = 0 # uint8_t 目标颜色标志位 shape = 0 # uint8_t 目标形状标志位 flag = 0 # uint8_t 目标标志位 mode = 0 # uint8_t 工作模式位 # 实例化类 K210 = K210_Property() # 实例化 K210_Property() 为 K210 # 串口发送测试信息赋值 #测试用信息 #fasong.mode = 1 #jieshou.mode = 1 #jieshou.x = 36 #jieshou.y = 26 #jieshou.color = 24 #jieshou.shape = 24 #jieshou.flag = 2 # 打印信息函数 # 打印 sensor 各参数 def Print_sensor(): print("Exposure :", sensor.get_exposure_us(), "Gain:", sensor.get_gain_db(), "RGB:", sensor.get_rgb_gain_db()) # 打印 K210 各参数 def Print_K210(): print("Mode:", K210.mode, "x:", K210.x, "y:", K210.y, "color:", K210.color, "shape:", K210.shape, "flag:", K210.flag) # 打印 色块 各参数 def Print_Blobs_Property(color,name): print(name,"cx:",color.cx,"cy:",color.cy,"flag:",color.flag,"color:",color.color,"density:",color.density,"led_flag:",color.led_flag) # 打印总函数 def Print_All(): print("______________________________________________________________________") Print_sensor() # 打印 sensor 参数 #Print_Blobs_Property(black,"Black ") # 打印 黑色色块 参数 #Print_Blobs_Property(red, "Red ") # 打印 红色色块 参数 Print_K210() # 打印 K210 参数 # LCD # LCD 初始化 lcd.init() # lcd初始化 # 串口数据打包方法函数 def UART_Pack_Method(TData): if TData.pack_flag == 1: data = bytearray([TData.head1, # 帧头1 TData.head2, # 帧头2 0x00, # 有效数据长度 0x00 + data_len - 4 TData.mode, # 保存目标x轴坐标 高八位 0x00]) # 数据和校验位 elif TData.pack_flag == 2: data = bytearray([TData.head1, # 帧头1 TData.head2, # 帧头2 0x00, # 有效数据长度 0x00 + data_len - 4 TData.x>>8, # 保存目标x轴坐标 高八位 TData.x, # 保存目标x轴坐标 低八位 TData.y>>8, # 保存目标y轴坐标 高八位 TData.y, # 保存目标y轴坐标 低八位 TData.color, # 保存目标颜色标志位 TData.shape, # 保存目标形状标志位 TData.flag, # 保存目标标志位 0x00]) # 数据和校验位 return data # 串口数据保存方法函数 def UART_Save_Method(PData): if PData.save_flag == 1 and PData.uart_buf[2] > 0: K210.mode = PData.uart_buf[3] elif PData.save_flag == 2 and PData.uart_buf[2] > 6: K210.x = PData.uart_buf[3]*256 + PData.uart_buf[4] K210.y = PData.uart_buf[5]*256 + PData.uart_buf[6] K210.color = PData.uart_buf[7] K210.shape = PData.uart_buf[8] K210.flag = PData.uart_buf[9] #颜色识别 #__________________________________________________________________ color_thresholds = [ (45, 57, -10, -3, 10, 19),#安全区 (24, 31, 29, 36, 17, 29),# red (28, 57, -21, -5, 19, 48), # yellow (24, 35, -11, 4, -28, -14),# Blue ] color_strings = ['1', '2', '3'] #1:red 2:yellow 3:bule color_zhongxin = dict.fromkeys(color_strings) color_anquanqu = [] #测距模块 #______________________________________________________________ ____# 摄像头参数(根据实际安装调整) CAMERA_HEIGHT = 110 # 摄像头离地高度(mm) CAMERA_ANGLE = 30 # 摄像头倾角(度) FOCAL_LENGTH = 540 # 重新标定的焦距(像素) # 图像中心点 CENTER_X = 160 CENTER_Y = 120 COLOR_THRESHOLDS= color_thresholds def calculate_distance(y_pos): """ 根据物体在图像中的y位置计算距离(考虑摄像头倾角) :param y_pos: 物体底部在图像中的y坐标 :return: 距离(毫米) """ # 计算垂直偏移(像素) offset_y = CENTER_Y - y_pos # 注意符号反转 # 计算角度偏移(弧度) angle_offset = math.atan(offset_y / FOCAL_LENGTH) # 计算总俯角(弧度) total_angle = math.radians(CAMERA_ANGLE) + angle_offset # 计算实际距离 distance = CAMERA_HEIGHT / math.sin(total_angle) horizontal_distance = distance * math.cos(total_angle) return horizontal_distance def find_target(blob): max_size = 0 target = None for b in blob: if b.pixels() > max_size: max_size = b.pixels() target = b return target def draw_info(img, target, distance): img.draw_rectangle(target.rect(), color=(255, 0, 0)) img.draw_cross(target.cx(), target.cy(), color=(0, 255, 0)) dist_text = "Dist: {:.0f}mm".format(distance) img.draw_string(10, 10, dist_text, color=(255, 0, 0), scale=1.5) img.draw_line(0, CENTER_Y, 320, CENTER_Y, color=(0, 0, 255)) img.draw_string(10, CENTER_Y - 20, "Horizon", color=(0, 0, 255)) img.draw_line(0, target.y() + target.h(), 320, target.y() + target.h(), color=(255, 0, 0)) # 主函数 #______________________________________________________________ while(True): clock.tick() img = sensor.snapshot() color_anquanqu = [] # 每次循环都清空安全区列表 color_zhongxin = {'1': None, '2': None, '3': None} # 初始化字典 for color_idx, threshold in enumerate(color_thresholds): blobs = img.find_blobs([threshold], pixels_threshold=100, area_threshold=100, merge=True, margin=10) if blobs: for blob in blobs: color_new = (255, 255, 255) if color_idx == 0: color_new = (120, 120, 120) color_anquanqu.append(blob.x()) color_anquanqu.append(blob.y()) color_anquanqu.append(blob.x() + blob.w()) color_anquanqu.append(blob.y() + blob.h()) # 安全区检查 in_safe_zone = False if len(color_anquanqu) >= 4 and : x_in_range = color_anquanqu[0] < blob.cx() < color_anquanqu[2] y_in_range = color_anquanqu[1] < blob.cy() < color_anquanqu[3] in_safe_zone = x_in_range and y_in_range if color_idx == 1 and not in_safe_zone: target = find_target(blob) color_new = (255, 0, 0) bottom_y = target.y() + target.h() distance = calculate_distance(bottom_y) color_zhongxin['1'] = [blob.cx(), blob.cy(), distance] elif color_idx == 2 and not in_safe_zone: target = find_target(blob) color_new = (0, 255, 0) bottom_y = target.y() + target.h() distance = calculate_distance(bottom_y) color_zhongxin['2'] = [blob.cx(), blob.cy(), distance] elif color_idx == 3 and not in_safe_zone: target = find_target(blob) color_new = (0, 0, 255) bottom_y = target.y() + target.h() distance = calculate_distance(bottom_y) color_zhongxin['3'] = [blob.cx(), blob.cy(),distance] img.draw_rectangle(blob.rect(), color=color_new, thickness=3) img.draw_cross(blob.cx(), blob.cy(), color=color_new) img.draw_string(blob.cx() + 10, blob.cy() - 10, color_strings[color_idx], color=color_new) lcd.display(img) # 发送检测到的色块数据 for s in range(1, 4): key = str(s) if color_zhongxin[key] is not None: jieshou.x = color_zhongxin[key][0] jieshou.y = color_zhongxin[key][1] jieshou.color = s jieshou.shape = 1 jieshou.flag = color_zhongxin[key][2] print(color_zhongxin[key]) #uart2.write(Pack_Data(jieshou)) color_zhongxin[key] = None time.sleep(1) Traceback (most recent call last): File "<stdin>", line 390 SyntaxError: invalid syntax MicroPython v0.6.2-89-gd8901fd22 on 2024-06-17; Sipeed_M1 with kendryte-k210 Type "help()" for more information.以上程序程序发生了如上报错,请分析原因,给出解决方案,并以提高识别精度为目的生成一份优化后的新python程序
最新发布
07-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值