摄像头视频输出偏蓝求助:硬编码坐标框画面异常
问题分析与解决方案
核心问题:颜色空间不匹配
OpenCV 从摄像头读取的帧是 BGR 格式,但 PIL 的 Image.fromarray() 方法默认期望输入是 RGB 格式。这直接导致了整体画面偏蓝——而边界框内的内容看起来正常,是因为你后续的轮廓绘制是在未转换颜色空间的clone帧上,但最终转成PIL图像时没做颜色转换,才出现了这种异常。
另外,代码里还有几处冗余和影响功能的小问题,我一起帮你修正。
具体修复步骤
添加BGR到RGB的颜色转换
在将OpenCV帧转换为PIL图像前,必须把BGR格式转成RGB,这是解决颜色偏蓝的关键:img1 = Image.fromarray(cv2.cvtColor(clone, cv2.COLOR_BGR2RGB))移除冗余的帧拷贝
原代码里连续两次clone = frame.copy(),第一次拷贝完全没有作用,直接删除即可:_, frame = vid.read() # 删掉这行无用的拷贝:clone = frame.copy() frame = cv2.flip(frame,1) clone = frame.copy()修正背景更新的权重值
你设置的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
相关产品推荐
相关产品推荐

