You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派3无人驾驶项目OpenCV cvtColor报错(-215) scn==3||4求助

问题分析与解决方案

我帮你排查下这个问题哈~你遇到的error: (-215) scn == 3 || scn == 4 in function cvtColor错误,本质是传入cv2.cvtColor()的图像不是有效的3通道(BGR)或4通道(BGRA)矩阵,而图像能成功存储是因为大部分时候摄像头能正常读取帧,报错只是偶尔读取失败的情况。下面具体说问题根源和修复方案:

问题根源

  1. 未检查摄像头帧读取状态
    你的代码里直接用cap.read()的返回值im,但没有判断ret是否为True。当摄像头初始化慢、偶尔丢帧,或者多线程竞争摄像头资源时,ret会是False,此时im是无效的空矩阵,传给cvtColor()就会触发这个错误。

  2. 线程与定时器逻辑混乱
    process_img()里先启动了一个定时器,然后又嵌套了while True循环;main()里还再次启动定时器调用process_img(),这会导致多个循环同时读取摄像头,加剧帧读取失败的概率,还会造成资源冲突。

  3. 全局变量使用不当
    你把gray设为全局变量,当某次帧读取失败时,gray没有被正确赋值,后续依赖gray的边缘检测逻辑也会出问题。

修复后的代码

下面是调整后的代码,我标注了关键修改点:

import numpy as np
import cv2
#import RPi.GPIO as GPIO

cap = cv2.VideoCapture(0)
i = 0
LEdge = 0
REdge = 0
lineErr = 0

#GPIO.setmode(GPIO.BOARD)
#GPIO.setup(12,GPIO.OUT)
#p = GPIO.PWM(12,100)
#p.start(0)

def fetch_img(image):
    global i
    # 这里只用局部变量gray,避免全局变量污染
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    img_gray_blur = cv2.GaussianBlur(gray, (5,5), 0)
    canny_edges = cv2.Canny(img_gray_blur, 10, 70)
    ret, mask = cv2.threshold(canny_edges, 90, 255, cv2.THRESH_BINARY)
    i += 1
    fn = '/home/alex/All IT Courses/Master Computer Vision OpenCV/images/img/'+str(i)+'.jpg'
    cv2.imwrite(fn, mask)
    return mask, gray

def process_img():
    global LEdge, REdge, lineErr
    # 去掉多余的定时器,用单一循环持续处理帧
    while True:
        ret, im = cap.read()
        # 关键:检查是否成功读取帧,失败则跳过本次循环
        if not ret:
            print("Failed to capture frame, skipping...")
            continue
        
        # 获取处理后的mask和有效灰度图
        mask, gray = fetch_img(im)
        cv2.imshow("Test", mask)
        
        # 边缘检测逻辑:基于有效灰度图处理
        for j in range(1, 640):
            gray[240][j] = 0 if gray[240][j] < 80 else 1
        
        # 初始化边缘值,避免未找到边缘时计算出错
        REdge = 320
        for k in range(320, 640, 1):
            if gray[240][k] == 0:
                REdge = k
                break
        
        LEdge = 320
        for k in range(320, 0, -1):
            if gray[240][k] == 0:
                LEdge = k
                break
        
        lineErr = (REdge + LEdge) / 2 - 320
        print(lineErr)
        
        if cv2.waitKey(1) == 13: # 13是Enter键的ASCII码
            break
    cap.release()
    cv2.destroyAllWindows()

def main():
    # 只启动一次处理循环,避免多线程竞争摄像头
    process_img()
    # 以下PWM控制代码可按需恢复
    # try:
    #     while 1:
    #         dc = 8 - lineErr/40
    #         if dc > 10:
    #             dc = 10
    #         if dc < 6:
    #             dc = 6
    #         p.ChangeDutyCycle(dc)
    # except KeyboardInterrupt:
    #     pass
    # p.stop()
    # GPIO.cleanup()

if __name__ == "__main__":
    main()

关键修改说明

  1. 添加帧读取状态检查:每次cap.read()后判断ret,无效帧直接跳过,避免传入无效图像给cvtColor()。
  2. 重构线程/定时器逻辑:去掉多余的定时器,用单一while True循环持续处理帧,避免多实例竞争摄像头资源。
  3. 优化变量作用域:把gray改为fetch_img()的局部变量,处理后返回有效灰度图,避免全局变量带来的赋值异常。
  4. 初始化边缘默认值:给LEdge和REdge设置默认值(画面中心),避免未检测到边缘时计算lineErr出错。

内容的提问来源于stack exchange,提问作者Alex M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:31:42