> 文章列表 > RGB转YCbCr——Python(1)

RGB转YCbCr——Python(1)

RGB转YCbCr——Python(1)

文章目录

  • 前言
  • 一、RGB转YCbCr
  • 二、Python端代码
  • 总结

前言

  本系列课程结合软件与硬件,以图像为主要研究对象。课程素材来源于《基于MATLAB与FPGA的图像处理教程》,并将MATLAB改成Python。


一、RGB转YCbCr

  RGB转YCbCr有以下几个标准,标准不同,转换公式不同,本文只给出标准3的转换公式。

  1. 标准清晰度电视(SDTV)
  2. 清晰度电视(HDTV)
  3. full range 或者 pc range

  full range 或者 pc range公式如下:
[YCbCr]=[0128128]+[0.2990.5870.114−0.169−0.3310.5000.500−0.419−0.081]×[RGB],其中{R/G/B∈[0,255]Y/Cb/Cr∈[0,255](1)\\begin{bmatrix} Y\\\\ Cb\\\\ Cr\\\\ \\end{bmatrix} = \\begin{bmatrix} 0\\\\ 128\\\\ 128\\\\ \\end{bmatrix} + \\begin{bmatrix} 0.299&0.587&0.114\\\\ -0.169&-0.331&0.500\\\\ 0.500&-0.419&-0.081\\\\ \\end{bmatrix} \\times \\begin{bmatrix} R\\\\ G\\\\ B\\\\ \\end{bmatrix},其中 \\begin{cases} R/G/B \\in &[0, 255]\\\\ Y/Cb/Cr \\in &[0, 255] \\end{cases}\\tag{1}YCbCr=0128128+0.2990.1690.5000.5870.3310.4190.1140.5000.081×RGB,其中{R/G/BY/Cb/Cr[0,255][0,255](1)

  为了方便FPGA硬件设计,需要对公式(1)进行稍微的转变。

Y=R×0.299+G×0.587+B×0.114(2)Y = R\\times0.299 + G\\times0.587+B\\times0.114\\tag{2} Y=R×0.299+G×0.587+B×0.114(2)
  将公式(2)扩大282^828=256倍。
256×Y=R×76.544+G×150.272+B×29.184≈R×76+G×150+B×29(3)256 \\times Y = R \\times 76.544 + G \\times 150.272 + B \\times 29.184 \\approx R\\times76 + G \\times150 + B \\times 29\\tag{3} 256×Y=R×76.544+G×150.272+B×29.184R×76+G×150+B×29(3)
  结果不能四舍五入,去掉小数即可,算出结果再通过向右移动8位缩小256倍得到Y。Cb,Cr同样的操作,如公式(4)所示。
{Y=(R×76+G×150+B×29)>>8Cb=(−R×43−G×84+B×128+32768)>>8Cb=(R×128−G×107−B×20+32768)>>8(4)\\begin{cases} Y = (R\\times76 + G \\times150 + B \\times 29)>>8\\\\ Cb = (-R\\times43 - G \\times84 + B \\times 128 + 32768)>>8\\\\ Cb = (R\\times128 - G \\times107 - B \\times 20 + 32768)>>8\\end{cases}\\tag{4} Y=(R×76+G×150+B×29)>>8Cb=(R×43G×84+B×128+32768)>>8Cb=(R×128G×107B×20+32768)>>8(4)

二、Python端代码

import matplotlib.pyplot as plt
import numpy as np
img = plt.imread("girl.jpg")#读取图像
h, w, _ = img.shape#获取高宽通道
img_ycbcr = np.zeros(img.shape)
for i in range(h):for j in range(w):img_ycbcr[i, j, 0] = (img[i, j, 0] * 76 + img[i, j, 1] * 150 + img[i, j, 2] * 29) >> 8img_ycbcr[i, j, 1] = ((-img[i, j, 0]) * 43 - img[i, j, 1] * 84 + img[i, j, 2] * 128 + 32768) >> 8img_ycbcr[i, j, 2] = (img[i, j, 0] * 128 - img[i, j, 1] * 107 - img[i, j, 2] * 20 + 32768) >> 8
#画图
plt.figure(figsize=(10, 10))
plt.subplot(221)
plt.title("RGB image")
plt.imshow(img)
plt.subplot(222)
plt.title("y channel")
plt.imshow(img_ycbcr[:, :, 0], cmap='gray')
plt.subplot(223)
plt.title("cb channel")
plt.imshow(img_ycbcr[:, :, 1], cmap='gray')
plt.subplot(224)
plt.title("cr channel")
plt.imshow(img_ycbcr[:, :, 2], cmap='gray')

在这里插入图片描述
  保存YCbCr图像。

img_ycbcr = img_ycbcr.astype(np.uint8)#float to int
plt.imsave("ycbcr.jpg", img_ycbcr)#保存转换后的图像

在这里插入图片描述
  将RGB与YCbCr以十六进制保存到.dat文件里面,供FPGA端代码测试。

import os
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image"""
把图像像素转hex写入.dat文件
"""
def write_file(arr, dat_file):arr_list = arr.tolist()f = open(dat_file, "a")for i in range(len(arr_list)):row_hex = ' '.join([hex(j)[2:] for j in arr_list[i]]) + '\\n'f.write(row_hex)f.close()"""
r,g,b全部写入文件
"""
def gen_dat(image_file, dat_file):image_file = os.path.join(os.getcwd(), image_file)dat_file = os.path.join(os.getcwd(), dat_file)if os.path.exists(dat_file):#如果存在,就删除.dat文件os.remove(dat_file)img =  Image.open(image_file)resized_image = img.resize((10,10))#由于原图太大,不便于观察r, g, b = resized_image.split()r_array = np.array(r)g_array = np.array(g)b_array = np.array(b)write_file(r_array, dat_file)write_file(g_array, dat_file)write_file(b_array, dat_file)if __name__ == "__main__":gen_dat("girl.jpg", "img_rgb.dat")gen_dat("ycbcr.jpg", "img_ycbcr.dat")

  原图过大,为了减少计数量,缩放至10x10,r是1到10行,g是11到20行,b是21到30行。

在这里插入图片描述

总结

  实现的代码还是有所区别,并不是和课本完成一致,但是目标是一致的,就如《基于MATLAB与FPGA的图像处理教程》中说到的,让你的软件起飞。下期将带来RGB转YCbCr——FPGA,敬请期待。