Python与FPGA——RGB2YCbCr


前言

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


一、RGB转YCbCr

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

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

  full range 或者 pc range公式如下:
[ Y C b C r ] = [ 0 128 128 ] + [ 0.299 0.587 0.114 − 0.169 − 0.331 0.500 0.500 − 0.419 − 0.081 ] × [ R G B ] , 其中 { R / G / B ∈ [ 0 , 255 ] Y / C b / C r ∈ [ 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)扩大 2 8 2^8 28=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 × 77 + G × 150 + B × 29 ) > > 8 C b = ( − R × 43 − G × 84 + B × 128 + 32768 ) > > 8 C r = ( R × 128 − G × 107 − B × 20 + 32768 ) > > 8 (4) \begin{cases} Y = (R\times77 + G \times150 + B \times 29)>>8\\ Cb = (-R\times43 - G \times84 + B \times 128 + 32768)>>8\\ Cr = (R\times128 - G \times107 - B \times 20 + 32768)>>8\end{cases}\tag{4} Y=(R×77+G×150+B×29)>>8Cb=(R×43G×84+B×128+32768)>>8Cr=(R×128G×107B×20+32768)>>8(4)

二、Python端代码

import matplotlib.pyplot as plt
import numpy as np
img = plt.imread("lenna.png")#读取图像
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) / 256
        img_ycbcr[i, j, 1] = ((-img[i, j, 0]) * 43 - img[i, j, 1] * 84 + img[i, j, 2] * 128 + 32768) / 256
        img_ycbcr[i, j, 2] = (img[i, j, 0] * 128 - img[i, j, 1] * 107 - img[i, j, 2] * 20 + 32768) / 256
#画图
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')

在这里插入图片描述

三、FPGA端代码

  verilog rgb888_to_ycbcr.v代码如下。

module  rgb888_to_ycbcr
(
	input	wire			vga_clk		,//vga时钟
	input	wire			sys_rst_n	,//复位信号
	input	wire	[7:0]	r			,//原图红色分量
	input	wire	[7:0]	g			,//原图绿色分量
	input	wire	[7:0]	b			,//原图蓝色分量
	
	output	reg		[7:0]	y			,//ycbcr中的y分量
	output	reg		[15:0]	gray_data   //vga 565
);
//Y = (77r + 150g + 29b) >> 8
//Cb = (-43r - 85g + 128b)>>8 + 128
//Cr = (128r - 107g - 21b)>>8 + 128
//其他两个分量放上面了
always@(posedge vga_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		y  <=  8'd0  ;
	else
		y  <=  (77 * r + 150 * g + 29 * b) >> 8  ;//根据公式4
		
always@(posedge vga_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		gray_data  <=  16'd0  ;
	else
		gray_data  <=  {y[7:3],y[7:2],y[7:3]}  ;//vga是16位,根据565从y分量高位到低位取出进行拼接

endmodule

  采集卡采集到FPGA输出的y分量图像。

在这里插入图片描述

  特意强调一下,由于课本中涉及到仿真,这里就不作仿真的讲解。FPGA端涉及到SDRAM、串口、VGA显示、按键控制、按键消抖、数码管显示、LED灯显示、异步FIFO、图像处理等多项内容。这些内容会在本教程《Python与FPGA》最后进行详细的讲解,目前只讨论图像处理相关代码。

总结

  实现的代码还是有所区别,并不是和课本完全一致,但是目标是一致的。就如《基于MATLAB与FPGA的图像处理教程》中说到的,让你的软件起飞。实验结果也是一样,按下按键,图像就被嗖的一下处理掉了,快到只能用xxxx形容。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值