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

16位RGGB格式Bayer编码Raw图像去马赛克处理问题求助

问题描述

我有一张分辨率为1200×1648、每个像素16位的RGGB格式Bayer编码Raw图像,解压读取后图像呈现偏绿状态,想了解后续应执行哪些图像处理步骤。尝试过simple-image-debayer和colour-demosaicing库,但得到的是全白图像,代码中if(bands == 1)分支无法生成正确的彩色图像,我认为偏绿现象是由RGGB颜色滤波阵列(CFA)导致的。

相关代码
image_path = "ZL0_0206_0685235537_613RAD_N0071836ZCAM08234_1100LMA02.IMG"

import os
import requests
from bs4 import BeautifulSoup
import struct
import numpy as np
import cv2
import matplotlib.pyplot as plt
import re
import os
import shutil
import time

import colour
from colour_demosaicing import demosaicing_CFA_Bayer_Malvar2004,demosaicing_CFA_Bayer_Menon2007     

#############  convert image to png  #############

def readHeader(file):
    # print("Calling readHeader")
    f = open(file,'rb')
    continuing = 1
    count = 0
    
    h_bytes = -1
    h_lines = -1
    h_line_samples = -1
    h_sample_type = 'UNSET' #MSB_INTEGER, IEEE_REAL
    h_sample_bits = -1
    h_bands = -1
    while continuing == 1:
        line = f.readline()
        count = count + 1
        arr = str(line, 'utf8').split("=")
        arr[0] = str(arr[0]).strip()
        if 'BYTES' == arr[0] and len(arr[0])>1:
            h_bytes=int(str(arr[1]).strip())
        elif 'LINES' == arr[0] and len(arr[0])>1: 
            h_lines=int(str(arr[1]).strip())
        elif 'LINE_SAMPLES' == arr[0] and len(arr[0])>1:
            h_line_samples=int(str(arr[1]).strip())
        elif 'SAMPLE_TYPE' == arr[0] and len(arr[0])>1:
            h_sample_type=str(arr[1]).strip()
        elif 'SAMPLE_BITS' == arr[0] and len(arr[0])>1:
            h_sample_bits = int(str(arr[1]).strip())
        elif 'BANDS' == arr[0] and len(arr[0])>1: 
            h_bands=int(str(arr[1]).strip())
        if (line.endswith(b'END\r\n') or count>600):
            continuing = 0
    f.close()
    return h_bytes, h_lines,h_line_samples,h_sample_type,h_sample_bits,h_bands

def readImage(file, pixelbytes, sample_type,sample_bits, lines, line_samples, bands):
    # print("Calling Read image")
    f = open(file,'rb')
    filesize = os.fstat(f.fileno()).st_size
    h_bytes = filesize - pixelbytes
    f.seek(h_bytes) # skip past the header bytes
    
    fmt = '{endian}{pixels}{fmt}'.format(endian='>', pixels=lines*line_samples*bands, fmt=getFmt(sample_type,sample_bits))
    
    if (bands==3):
        print(pixelbytes,lines,line_samples,fmt)
        img = np.array(struct.unpack(fmt,f.read(pixelbytes))).reshape(bands,lines,line_samples)    
        print(img)
        m = np.max(np.max(img, axis=1))
        img = np.clip(img/m,0,1) #normalize and clip so values are between 0 and 1
        img = np.stack([img[0,:,:],img[1,:,:],img[2,:,:]],axis=2)
        # print(img.shape)

    elif (bands==1):
        print(pixelbytes,lines,line_samples,fmt)
        img = np.array(struct.unpack(fmt,f.read(pixelbytes))).reshape(lines,line_samples)    
        # data = np.fromfile(f, np.uint8, line_samples * lines * 3//2)
        # data = data.astype(np.uint16)  # Cast the data to uint16 type.
        # result = np.zeros(data.size*2//3, np.uint16)
        # img = np.array(struct.unpack(fmt,f.read(pixelbytes))).reshape(lines,line_samples)    
        # result[0::2] = ((data[1::3] & 15) << 8) | data[0::3]
        # result[1::2] = (data[1::3] >> 4) | (data[2::3] << 4)
        # bayer_im = np.reshape(result, (lines, line_samples))
        img = cv2.cvtColor(np.uint16(img), cv2.COLOR_BAYER_BG2BGR)

    return img
    # return img
    
    
# fmtMap - converts sample_type from header to python format fmt. 
def getFmt(sample_type, samplebits):
    # print("Calling getFM funtion")
    if (sample_type=='IEEE_REAL'):
        return 'f'
    elif (sample_type=='MSB_INTEGER'):
        return 'H'
    elif (sample_type=='UNSIGNED_INTEGER'):
        return 'B'
    else:
        return 'X'



def convert_to_png(sol_folder_path):

  hbytes,hlines,hline_samples,hsample_type,hsample_bits,hbands = readHeader(full_path)
  numpixels = hlines * hline_samples * hbands
  pixelbytes = numpixels*hsample_bits//8 # // is for integer division
            
  img = readImage(full_path, pixelbytes, hsample_type,hsample_bits, hlines, hline_samples, hbands)
  plt.imsave('debayer_test.png',np.uint8(img))
问题分析与解决步骤

核心问题定位

  1. Bayer格式不匹配:代码中使用cv2.COLOR_BAYER_BG2BGR进行去马赛克,但图像是RGGB格式,格式不匹配直接导致颜色偏移,出现偏绿现象。
  2. 16位数据未归一化:读取的Raw数据是16位(范围0-65535),直接转uint8会丢失大部分动态范围,要么过曝成全白,要么对比度极低。
  3. colour-demosaicing库使用错误:该库默认处理0-1范围的float数据,直接传入16位uint数据会因数值过大被截断为1,导致全白图像。

修正步骤

1. 修正Bayer格式转换

将cv2.COLOR_BAYER_BG2BGR替换为cv2.COLOR_BAYER_RG2BGR,对应RGGB颜色滤波阵列的排列:

# 在bands==1分支中修改
img = cv2.cvtColor(img, cv2.COLOR_BAYER_RG2BGR)

2. 正确归一化16位数据

在去马赛克后(或去马赛克前)对16位数据进行归一化,将其映射到0-255范围的uint8:

# 方式1:线性归一化
img_normalized = (img / 65535.0 * 255).astype(np.uint8)

# 方式2:百分位截断(优化对比度,避免极端亮暗值影响)
p_low, p_high = np.percentile(img, (1, 99))
img_normalized = np.clip((img - p_low) / (p_high - p_low) * 255, 0, 255).astype(np.uint8)

3. 正确使用colour-demosaicing库

先将16位数据转换为0-1范围的float类型,再调用去马赛克函数:

# 在bands==1分支中替换原有代码
img_float = img.astype(np.float32) / 65535.0
# 使用RGGB格式去马赛克,可选Malvar2004或Menon2007算法
img_color = demosaicing_CFA_Bayer_Malvar2004(img_float, 'RGGB')
# 转换为uint8用于保存
img_normalized = (img_color * 255).astype(np.uint8)

4. 后续可选图像处理步骤

  • 白平衡调整:根据场景调整RGB通道的增益,比如手动设置红、蓝通道的倍数,修正剩余偏色
  • 色彩校正:使用相机的色彩矩阵将Raw颜色转换为sRGB标准色彩空间
  • 降噪处理:Raw图像通常存在噪声,可使用双边滤波、非局部均值滤波或专门的Raw降噪算法优化画质
  • 对比度增强:通过直方图均衡化、伽马校正等方式提升图像视觉效果

修正后的完整代码片段(关键部分)

def readImage(file, pixelbytes, sample_type,sample_bits, lines, line_samples, bands):
    f = open(file,'rb')
    filesize = os.fstat(f.fileno()).st_size
    h_bytes = filesize - pixelbytes
    f.seek(h_bytes)
    
    fmt = '{endian}{pixels}{fmt}'.format(endian='>', pixels=lines*line_samples*bands, fmt=getFmt(sample_type,sample_bits))
    
    if (bands==3):
        # 原有3通道处理逻辑不变
        img = np.array(struct.unpack(fmt,f.read(pixelbytes))).reshape(bands,lines,line_samples)    
        m = np.max(np.max(img, axis=1))
        img = np.clip(img/m,0,1)
        img = np.stack([img[0,:,:],img[1,:,:],img[2,:,:]],axis=2)

    elif (bands==1):
        img = np.array(struct.unpack(fmt,f.read(pixelbytes))).reshape(lines,line_samples)    
        # 方案1:使用OpenCV修正去马赛克
        img_color = cv2.cvtColor(img, cv2.COLOR_BAYER_RG2BGR)
        # 归一化处理
        p_low, p_high = np.percentile(img_color, (1, 99))
        img_normalized = np.clip((img_color - p_low) / (p_high - p_low) * 255, 0, 255).astype(np.uint8)
        
        # 方案2:使用colour-demosaicing库
        # img_float = img.astype(np.float32) / 65535.0
        # img_color = demosaicing_CFA_Bayer_Malvar2004(img_float, 'RGGB')
        # img_normalized = (img_color * 255).astype(np.uint8)
        
        return img_normalized

    return img

def convert_to_png(sol_folder_path):
    # 补充定义full_path
    full_path = image_path
    hbytes,hlines,hline_samples,hsample_type,hsample_bits,hbands = readHeader(full_path)
    numpixels = hlines * hline_samples * hbands
    pixelbytes = numpixels*hsample_bits//8
            
    img = readImage(full_path, pixelbytes, hsample_type,hsample_bits, hlines, hline_samples, hbands)
    plt.imsave('debayer_test.png', img)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 16:46:37