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

摄像头视频输出偏蓝求助:硬编码坐标框画面异常

问题分析与解决方案

核心问题:颜色空间不匹配

OpenCV 从摄像头读取的帧是 BGR 格式,但 PIL 的 Image.fromarray() 方法默认期望输入是 RGB 格式。这直接导致了整体画面偏蓝——而边界框内的内容看起来正常,是因为你后续的轮廓绘制是在未转换颜色空间的clone帧上,但最终转成PIL图像时没做颜色转换,才出现了这种异常。

另外,代码里还有几处冗余和影响功能的小问题,我一起帮你修正。


具体修复步骤

  1. 添加BGR到RGB的颜色转换
    在将OpenCV帧转换为PIL图像前,必须把BGR格式转成RGB,这是解决颜色偏蓝的关键:

    img1 = Image.fromarray(cv2.cvtColor(clone, cv2.COLOR_BGR2RGB))
    
  2. 移除冗余的帧拷贝
    原代码里连续两次clone = frame.copy(),第一次拷贝完全没有作用,直接删除即可:

    _, frame = vid.read()
    # 删掉这行无用的拷贝:clone = frame.copy()
    frame = cv2.flip(frame,1)
    clone = frame.copy()
    
  3. 修正背景更新的权重值
    你设置的aWeight = 0会导致背景完全无法更新(cv2.accumulateWeighted的权重为0时,背景不会变化),建议改成合理的值,比如:

    aWeight = 0.5
    

修改后的完整代码

import cv2
import numpy as np
import tkinter as tk
from PIL import ImageTk, Image

def keluar():
    app.destroy()
    cv2.destroyAllWindows()
    vid.release()
    print("quiting...")

def stream1():
    global num_frames
    _, frame = vid.read()
    frame = cv2.flip(frame, 1)
    clone = frame.copy()
    (height, width) = frame.shape[:2]
    frame1 = frame[top:bottom, right:left]
    frame2 = cv2.cvtColor(frame1, cv2.COLOR_BGR2HSV)
    frame3 = cv2.inRange(frame2, lower, upper)
    frame4 = cv2.GaussianBlur(frame3, (5,5), 0)
    
    if num_frames < 30:
        run_avg(frame4, aWeight)
    else:
        hand = segment(frame4)
        if hand is not None:
            (thd, segmented) = hand
            cv2.drawContours(clone, [segmented + (right, top)], -1, (0, 0, 255))
            cv2.imshow("Thesholded", thd)
    
    cv2.rectangle(clone, (left, top), (right, bottom), (0,255,0), 2)
    num_frames += 1
    
    # 关键修改:添加BGR转RGB的颜色转换
    img1 = Image.fromarray(cv2.cvtColor(clone, cv2.COLOR_BGR2RGB))
    imgtk1 = ImageTk.PhotoImage(image=img1)
    lframe.imgtk = imgtk1
    lframe.configure(image=imgtk1)
    lframe.after(1, stream1)

def run_avg(image, aWeight):
    global bg
    if bg is None:
        bg = image.copy().astype("float")
        return
    cv2.accumulateWeighted(image, bg, aWeight)

def segment(image, threshold=25):
    global bg
    diff = cv2.absdiff(bg.astype("uint8"), image)
    thd = cv2.threshold(diff, threshold, 255, cv2.THRESH_BINARY)[1]
    (_, cnts, _) = cv2.findContours(thd.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    if len(cnts) == 0:
        return
    else:
        segmented = max(cnts, key=cv2.contourArea)
        return (thd, segmented)

# 修改权重值,让背景可以正常更新
aWeight = 0.5
num_frames = 0
top, right, bottom, left = 10, 350, 225, 590
bg = None
vid = cv2.VideoCapture(0)

app = tk.Tk()
kotak = tk.Frame(app, bg="white")
kotak.grid()

lframe = tk.Label(kotak)
lframe.grid(column=0, row=0)

lframe2 = tk.Label(kotak, text="Output", font=("arial",20))
lframe2.grid(column=2, row=0, rowspan=2, padx=20, pady=20)

bstart = tk.Button(kotak, text="Start")
bstart.grid(column=0, row=1, columnspan=2, ipadx=100, ipady=50, padx=20, pady=20)

bexit = tk.Button(kotak, text="Exit", command=keluar)
bexit.grid(column=1, row=1, columnspan=2, ipadx=50, ipady=30, padx=20, pady=20)

kernel = np.ones((5,5),np.uint8)
lower = np.array([0, 58, 50])
upper = np.array([30, 255, 255])

stream1()
app.mainloop()

验证说明

运行修改后的代码后,视频画面的颜色应该会恢复正常,边界框和手部轮廓的绘制也能正常显示。另外,背景更新功能现在也能正常工作,有助于后续的手部分割逻辑更准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:15:14