深圳国贸网站建设,php装修公司网站源码,东莞网站建设网站建设多少钱,想要一个免费的网站在数字图像处理中#xff0c;Gamma 变换是一种重要的灰度变换方法#xff0c;可以用于图像增强与 Gamma 校正。本文主要介绍数字图像 Gamma 变换的基本原理#xff0c;并记录在紫光同创 PGL22G FPGA 平台的布署与实现过程。 目录
1. Gamma 变换原理
2. FPGA 布署与实现
2… 在数字图像处理中Gamma 变换是一种重要的灰度变换方法可以用于图像增强与 Gamma 校正。本文主要介绍数字图像 Gamma 变换的基本原理并记录在紫光同创 PGL22G FPGA 平台的布署与实现过程。 目录
1. Gamma 变换原理
2. FPGA 布署与实现
2.1 功能与指标定义
2.2 模块设计
2.3 上板调试 1. Gamma 变换原理 在摄像机成像过程中人们使用了 Gamma 编码对图像进行处理这样做的好处是能更好地记录与存储图像。 采用 Gamma 编码的图像在显示器上显示时需要进行 Gamma 校正以还原图像。 Gamma 校正可以用以下变换公式表示 其中 是输入图像某一点的亮度值 是输出图像上对应点的亮度值。 1当 0 gamma 1 时图像在低灰度值区域动态范围变大整体图像的灰度值变大
2当 gamma 1 时图像在高灰度值区域动态范围变大整体图像的灰度值变小。 使用 Matlab 进行验证代码如下
clc, clear% 读取图像
im imread(./loopy.png);
im im2double(im);% gamma变换
invgamma 2.2;
gamma 1/invgamma;
im_new im.^gamma;subplot(121)
imshow(im2uint8(im))
title(原图像)
subplot(122)
imshow(im2uint8(im_new))
title(处理后图像) 参考链接Understanding Gamma Correction (cambridgeincolour.com) 2. FPGA 布署与实现
2.1 功能与指标定义 使用紫光同创 FPGA 平台实现 Gamma 变换功能FPGA 需要实现的功能与指标如下
1与电脑的串口通信用于接收上位机下发的 Gamma 曲线和原始图像波特率为 256000 Bd/s
2Gamma 变换使用 FPGA 嵌入式 RAM实现 Gamma 曲线的缓存与查表
3DDR3 读写控制将处理前后的图像数据分别写入 DDR3 的不同区域实现图像的拼接
4HDMI 输出输出一路 HDMI 信号源用于将拼接后的图像显示在外接显示器上分辨率为 1024×768。 2.2 模块设计 主要的设计模块层次与功能说明如下 模块名称功能说明top_uartuart_rx_slice串口接收驱动模块uart_rx_parse串口数据解析模块从上位机接收 8bit 原始图像以及 Gamma 曲线数据top_vidinvidin_pipeline缓存两行图像数据并将数据提交到 ddr3 数据调度模块conv_gammaGamma 变换模块使用 DPRAM 存储器进行 Gamma 查表merge_outdvi_timing_genHDMI 视频时序产生模块dvi_ddr_rd根据 HDMI 控制信号提交读指令到 ddr3 数据调度模块dvi_encoderHDMI 输出编码8b10b 编码与输出驱动模块 其中conv_gamma 模块主要使用 dpram 查表的方式对原始图像的 RGB 分量分别进行 Gamma 变换模块代码如下
timescale 1 ns/ 1 psmodule conv_gamma (// System levelsys_rst,sys_clk,// Gamma parameter inputpara_gamma_waddr,para_gamma_data,para_gamma_wren,// Gamma data input and outputgamma_in_data,gamma_out_data
);// IO direction/register definitions
input sys_rst;
input sys_clk;
input [7:0] para_gamma_waddr;
input [7:0] para_gamma_data;
input para_gamma_wren;
input [23:0] gamma_in_data;
output [23:0] gamma_out_data;// internal signal declarations
reg [7:0] blk_mem_waddr;
reg [7:0] blk_mem_wdata;
reg blk_mem_wren;// gamma_dpram_inst_r: Block dpram for gamma data buffer
blk_mem_256x8b_gamma gamma_dpram_inst_r (.wr_data (blk_mem_wdata ), // input 8-bit.wr_addr (blk_mem_waddr ), // input 8-bit.wr_en (blk_mem_wren ), // input 1-bit.wr_clk (sys_clk ), // input 1-bit.wr_rst (sys_rst ), // input 1-bit.rd_addr (gamma_in_data[2*8:8] ), // input 8-bit.rd_data (gamma_out_data[2*8:8] ), // output 8-bit.rd_clk (sys_clk ), // input 1-bit.rd_rst (sys_rst ) // input 1-bit
);
// End of gamma_dpram_inst_r instantiation// gamma_dpram_inst_g: Block dpram for gamma data buffer
blk_mem_256x8b_gamma gamma_dpram_inst_g (.wr_data (blk_mem_wdata ), // input 8-bit.wr_addr (blk_mem_waddr ), // input 8-bit.wr_en (blk_mem_wren ), // input 1-bit.wr_clk (sys_clk ), // input 1-bit.wr_rst (sys_rst ), // input 1-bit.rd_addr (gamma_in_data[1*8:8] ), // input 8-bit.rd_data (gamma_out_data[1*8:8] ), // output 8-bit.rd_clk (sys_clk ), // input 1-bit.rd_rst (sys_rst ) // input 1-bit
);
// End of gamma_dpram_inst_g instantiation// gamma_dpram_inst_b: Block dpram for gamma data buffer
blk_mem_256x8b_gamma gamma_dpram_inst_b (.wr_data (blk_mem_wdata ), // input 8-bit.wr_addr (blk_mem_waddr ), // input 8-bit.wr_en (blk_mem_wren ), // input 1-bit.wr_clk (sys_clk ), // input 1-bit.wr_rst (sys_rst ), // input 1-bit.rd_addr (gamma_in_data[0*8:8] ), // input 8-bit.rd_data (gamma_out_data[0*8:8] ), // output 8-bit.rd_clk (sys_clk ), // input 1-bit.rd_rst (sys_rst ) // input 1-bit
);
// End of gamma_dpram_inst_b instantiationalways (posedge sys_rst or posedge sys_clk) beginif (sys_rst) beginblk_mem_waddr {8{1b0}};blk_mem_wdata 8h00;blk_mem_wren 1b0;endelse beginblk_mem_waddr para_gamma_waddr;blk_mem_wdata para_gamma_data;blk_mem_wren para_gamma_wren;end
end
endmodule2.3 上板调试 使用 PyQt5 和 OpenCV 库编写上位机程序通过串口发送 Gamma 曲线和原始图像数据代码如下
# -*- Coding: UTF-8 -*-
import cv2
import sys
import struct
import numpy as np
import pyqtgraph as pg
from PyQt5 import Qt, QtGui, QtCore, QtWidgets, QtSerialPortclass sliderWindow(Qt.QWidget):def __init__(self, parentNone):super(sliderWindow, self).__init__(parent)self.setGeometry(1250, 320, 400, 400)self.setWindowTitle(Slider Window)# 创建绘图窗口self.plot_graph pg.PlotWidget()self.plot_graph.setBackground(#303030)self.plot_graph.setXRange(0,1)self.plot_graph.setYRange(0,1)self.plot_graph.showGrid(xTrue, yTrue)gray np.linspace(0, 1, 255)gamma np.array(np.power(gray, 1))self.pen pg.mkPen(color(255, 255, 255), width5, styleQtCore.Qt.SolidLine)self.plot_graph.plot(gray, gamma)# 创建底部滑动条self.label QtWidgets.QLabel(1.00)self.slider QtWidgets.QSlider(QtCore.Qt.Horizontal)self.slider.setMinimum(20)self.slider.setMaximum(400)self.slider.setValue(100)#self.slider.setSingleStep(1)self.slider.setTickInterval(10)self.slider.setTickPosition(QtWidgets.QSlider.TicksBelow)self.slider.valueChanged.connect(self.valueChanged)bottomLayout QtWidgets.QHBoxLayout()bottomLayout.addWidget(self.label)bottomLayout.addWidget(self.slider)# 创建中心布局centralLayout QtWidgets.QVBoxLayout()centralLayout.addWidget(self.plot_graph)centralLayout.addLayout(bottomLayout)self.setLayout(centralLayout)def valueChanged(self):更新参数值if self.slider.value() 0:float_value 0.01else:float_value self.slider.value() /100.0self.label.setText({:.2f}.format(float_value))self.updatePlot(float_value)def updatePlot(self, gamma):gray np.linspace(0,1,255)gray_gamma np.array(np.power(gray, 1/gamma))self.plot_graph.clear()self.plot_graph.plot(gray, gray_gamma)class mainWindow(Qt.QWidget):def __init__(self, com_port, parentNone):super(mainWindow, self).__init__(parent)self.setFixedSize(530, 384)self.setWindowTitle(PGL OpenCV Tool)# 创建标签与按钮self.img_widget QtWidgets.QLabel()self.btn1 QtWidgets.QPushButton(打开)self.btn1.clicked.connect(self.getfile)self.btn2 QtWidgets.QPushButton(关闭)self.btn2.clicked.connect(self.close)# 创建布局centralLayout QtWidgets.QVBoxLayout()centralLayout.addWidget(self.img_widget)bottomLayout QtWidgets.QHBoxLayout()bottomLayout.addWidget(self.btn1)bottomLayout.addWidget(self.btn2)centralLayout.addLayout(bottomLayout)self.setLayout(centralLayout)# 串口对象self.COM QtSerialPort.QSerialPort()self.COM.setPortName(com_port)self.COM.setBaudRate(256000)self.open_status Falseself.row_cnt 0self.img Noneself.timer QtCore.QTimer()self.timer.timeout.connect(self.sendImage)self.startup()def startup(self):Write code here to run onceself.slider_window sliderWindow()self.slider_window.slider.valueChanged.connect(self.transformGamma)self.slider_window.slider.valueChanged.connect(self.sendGamma)for com_port in QtSerialPort.QSerialPortInfo.availablePorts():print(com_port.portName())# Try open serial portif not self.COM.open(QtSerialPort.QSerialPort.ReadWrite):self.open_status Falseprint(Open Serial Port failed.)else:self.open_status Truedef getfile(self):获取图像路径fname QtWidgets.QFileDialog.getOpenFileName(self, Open file,C:\\Users\\Administrator\\Pictures, Image files(*.jpg *.png))self.clipImage(fname[0])self.updateImage()self.sendImage()def clipImage(self, fname):读取并裁剪图片至512x384大小if fname:img cv2.imread(fname, cv2.IMREAD_COLOR)img_roi img[:384,:512,:]print(img_roi.shape)cv2.imwrite(./img_roi.png, img_roi)def transformGamma(self):Gamma变换if self.slider_window.slider.value() 0:invgamma 0.01else:invgamma self.slider_window.slider.value() /100.0gamma 1/invgammaimg_trans np.array(np.power(self.img/255, gamma)*255, dtypenp.uint8)cv2.imwrite(./img_gamma.png, img_trans)self.img_widget.setPixmap(QtGui.QPixmap(./img_gamma.png))def updateImage(self):显示裁剪后的图像self.img cv2.imread(./img_roi.png)# 判断显示原图像还是Gamma变换后的图像if self.slider_window.slider.value() 100:self.img_widget.setPixmap(QtGui.QPixmap(./img_roi.png))else:self.transformGamma()if self.open_status:self.timer.start(100)def sendImage(self):通过串口发送图片pattern 2H{:d}B.format(512*3)if self.open_status:if self.row_cnt 384:self.row_cnt 0self.timer.stop()else:args1 [0x5500, self.row_cnt]args2 [rgb for rgb in self.img[self.row_cnt,:].reshape(-1)]send_data struct.pack(pattern, *(args1args2))self.row_cnt 1self.COM.write(send_data)def sendGamma(self):通过串口发送Gamma曲线if self.slider_window.slider.value() 0:invgamma 0.01else:invgamma self.slider_window.slider.value() /100.0gamma 1/invgammagamma_f lambda x: np.uint8(np.floor(np.power(x/255, gamma)*255))pattern 1H{:d}B.format(256)if self.open_status:args1 [0xAA00]args2 [gamma_f(x) for x in range(256)]send_data struct.pack(pattern, *(args1args2))self.COM.write(send_data)def closeEvent(self, event):super().closeEvent(event)self.slider_window.close() # 关闭子窗口# 定时器停止self.timer.stop()if self.open_status:self.COM.close() # 关闭串口def main():app QtWidgets.QApplication(sys.argv)window mainWindow(COM21)for win in (window, window.slider_window):win.show()sys.exit(app.exec_())if __name__ __main__:main()连接串口线与 HDMI 线拖动滑动条改变 Gamma 值上位机程序会自动发送 Gamma 曲线到开发板然后发送要显示的图像就可以看到 FPGA 处理的效果了 ~