案例1 绿边
故障分析:
这个能明显看到视频上方出现绿色半透明边带。这说明Y数据正常。UV数据不正常。
它显然与视频帧的垂直分辨率设置有关。
UV数据和Y数据是连续放置的,如果上方出现彩色数据失调,说明这部分数据实际仍然是Y数据。也就是说如果这是1920*1080p的数据,那么说明它的线数比1080更大。
根据绿边行数/2,加至1080的数据上,故障消失:
案例2 栅格
故障分析
上面的配置下,出现水平数据的错位,在上面可以正常的显示被拆分成了3个带状的数据。YUV模式下不好看故障的特征,先把UV数据消掉,用标准的灰度图像去观察:
相关的灰度UV数据生成:
uv_plane = np.full((height // 2, width), 128, dtype=np.uint8)
最终根据灰度图上的关键点位的相对位置,得到了真正的width,修正后:
附录 A 16*16宏块分散的视频数据重组为标准YUV-420
这段代码没有用到,备用。本来是为了处理案例2.
def merge_to_yuv420(self, macrobloc_data, width, height):# Calculate sizesY_size = width * heightU_size = Y_size // 4 # U and V are quarter size of Y# Initialize arrays for Y, U, VY = np.empty((height, width), dtype=np.uint8)U = np.empty((height // 2, width // 2), dtype=np.uint8)V = np.empty((height // 2, width // 2), dtype=np.uint8)# Merge macroblocks into Y, U, V componentsfor r in range(height // 16):for c in range(width // 16):macroblock_index = r * (width // 16) + cY_block_start = macroblock_index * 256U_block_start = Y_size + (macroblock_index * 64)V_block_start = Y_size + U_size + (macroblock_index * 64)# Merge Y blockY[r*16:(r+1)*16, c*16:(c+1)*16] = np.frombuffer(macrobloc_data[Y_block_start:Y_block_start+256], dtype=np.uint8).reshape(16, 16)# Merge U and V blocksU[r*8:(r+1)*8, c*8:(c+1)*8] = np.frombuffer(macrobloc_data[U_block_start:U_block_start+64], dtype=np.uint8).reshape(8, 8)V[r*8:(r+1)*8, c*8:(c+1)*8] = np.frombuffer(macrobloc_data[V_block_start:V_block_start+64], dtype=np.uint8).reshape(8, 8)return Y, U, Vdef nv12_to_rgb(self, nv12, width, height):width = 1920height = 1080Y,U,V = self.merge_to_yuv420(nv12, width, height)U_upsampled = cv2.resize(U, (width, height), interpolation=cv2.INTER_LINEAR)V_upsampled = cv2.resize(V, (width, height), interpolation=cv2.INTER_LINEAR)yuv_image = np.concatenate((Y, U_upsampled, V_upsampled))# Use OpenCV to convert YUV420sp (NV12) to RGBrgb_image = cv2.cvtColor(yuv_image, cv2.COLOR_YUV2RGB_IYUV)return rgb_image