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

视频帧(NumPy数组)转PyTorch张量后旋转出现颜色异常、黑屏问题求助

视频帧(NumPy数组)转PyTorch张量后旋转出现颜色异常、黑屏问题求助

我太懂你这种折腾到崩溃的感觉了!ChatGPT越绕越乱的时候真的想摔键盘,咱们一步步拆解你代码里的问题,顺便解决你想直接旋转张量的需求~

先搞清楚两个核心问题的根源

1. 颜色异常:通道顺序+来回转换的逻辑混乱

你用cv2.VideoCapture读的帧是BGR格式,但PIL和PyTorch默认都是RGB格式,你转张量的时候没做通道转换,后续转PIL显示自然颜色全错。再加你的tensor_to_image函数里来回在PIL和cv2之间转,反而把通道绕得更乱了。

2. 黑屏:数值范围不匹配

你用transforms.ToTensor()把旋转后的PIL图转成张量时,这个函数会自动把0-255的像素值归一化到0-1的float类型,但你的check_tensor函数直接调用.byte(),等于把0-1的小数强制转成uint8,大部分值都会变成0,自然显示黑屏!


修正后的代码片段

第一步:修正帧转张量的逻辑(统一通道+数值范围)

读帧后转张量时,先把BGR转成RGB,同时统一数值范围(推荐用0-1的float,符合PyTorch的常用规范):

def analyze_video(self, video_path):
    video_capture = cv2.VideoCapture(video_path)

    for i in range(1):
        ret, frame = video_capture.read()
        if not ret:
            break

        # 修正:把BGR转RGB,同时归一化到0-1的float
        frame_rgb = frame[...,::-1].copy()  # BGR转RGB
        frame_tensor = torch.from_numpy(frame_rgb).float() / 255.0
        frame_tensor = frame_tensor.permute(2, 0, 1).unsqueeze(0)  # 转成(1,3,H,W)的张量格式

        self.check_tensor(frame_tensor)
  
        orig_prediction = self.analyze_frame(frame_tensor)
   
        rotated_tensor = im.rotate_tensor(frame_tensor, orig_prediction.head())
        self.check_tensor(rotated_tensor)

第二步:修正check_tensor函数(适配数值范围+通道转换)

显示时要把RGB转回BGR给cv2用,同时先把0-1的张量转回0-255的uint8:

def check_tensor(self, frame_tensor):
    # 先判断张量是0-1还是0-255范围,转回0-255的uint8
    if frame_tensor.dtype == torch.float32 and frame_tensor.max() <= 1.0:
        frame_numpy = (frame_tensor.squeeze(0).permute(1, 2, 0) * 255).byte().numpy()
    else:
        frame_numpy = frame_tensor.squeeze(0).permute(1, 2, 0).byte().numpy()
    
    # RGB转BGR适配cv2的显示要求
    frame_numpy = cv2.cvtColor(frame_numpy, cv2.COLOR_RGB2BGR)
    
    cv2.imshow("Frame", frame_numpy)
    cv2.waitKey(0)   
    cv2.destroyAllWindows()

第三步:修正rotate_tensor函数(解决颜色问题)

转PIL时先处理好张量的数值范围和通道,避免颜色错误:

def rotate_tensor(frame_tensor, landmarks):
    roll = calc_face_angle(landmarks)
    
    # 把0-1的张量转回RGB格式的uint8数组,再转PIL
    frame_np = (frame_tensor.squeeze(0).permute(1,2,0) * 255).byte().numpy()
    frame = Image.fromarray(frame_np)
    frame.show()  # 现在颜色应该正常了

    if not np.isnan(roll):
        rotated_frame = frame.rotate(roll, resample=Image.BICUBIC, expand=True)
    else:
        print("Failed to calculate face angle for rotation")
        return frame_tensor

    # 转回0-1的张量,保持和输入一致的格式
    transform = transforms.ToTensor()
    rotated_tensor = transform(rotated_frame).unsqueeze(0)
    return rotated_tensor

你的第二个问题:能不能直接旋转张量,不用转PIL?

当然可以!用torchvision.transforms.functional里的rotate函数直接操作张量,效率更高,还能避免来回转换的麻烦:

from torchvision.transforms.functional import rotate

def rotate_tensor_directly(frame_tensor, landmarks):
    roll = calc_face_angle(landmarks)
    if np.isnan(roll):
        print("Failed to calculate face angle for rotation")
        return frame_tensor
    
    # 直接旋转张量,expand=True会自动调整尺寸避免裁剪
    rotated_tensor = rotate(frame_tensor.squeeze(0), angle=roll, resample=Image.BICUBIC, expand=True).unsqueeze(0)
    return rotated_tensor

最后再划几个重点

  • 时刻记住cv2是BGR,PyTorch/PIL是RGB,转换时一定要对应调整通道顺序
  • 数值范围要统一:要么全程0-255的uint8,要么0-1的float,别混着来
  • 直接操作张量比转PIL效率高,尤其是处理大量帧的时候

备注:内容来源于stack exchange,提问作者Мария Шипаева

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 17:58:08