
图像对比度调整
=========================================

实验介绍
=========================================
直方图均衡技术将原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布,是一种常用的图像增强方法。
首先,我们需要将RGB888图像转化为YCrCb,统计当前Y分量直方图分布（应用于下一帧）,并通过上一帧的统计数据均衡化当前Y分量,再转换回RGB888并输出。

模块主要代码
=========================================

.. code:: c

  #include "contrastadj.h"

  void ExtractPixel(XF_TNAME(XF_8UC3,XF_NPPC1) &src_axi,ap_uint<8> dst[3])
  {
  	unsigned int i,j=0;
  	for(i=0;i<24;i+=8)
  	{
  #pragma HLS PIPELINE
  		dst[j]=src_axi.range(i+7,i);
  		j++;
  	}
  }
  
  void PackPixel(XF_TNAME(XF_8UC3,XF_NPPC1)&dst_axi,ap_uint<8>src[3])
  {
  	unsigned int i,j=0;
  	for(i=0;i<24;i+=8)
  	{
  #pragma HLS PIPELINE
  		dst_axi.range(i+7,i)=src[j];
  		j++;
  	}
  }
  
  template<int ROWS, int COLS, int N>
  void dualAryEqualize(
  		xf::cv::Mat<XF_8UC3,ROWS, COLS,XF_NPPC1>	&_src,
  		xf::cv::Mat<XF_8UC3,ROWS, COLS,XF_NPPC1>	&_dst,
  		int filter)
  {
  	static ap_uint<8> map[N];
  	ap_uint<32>hist_out1[N];
  #pragma HLS ARRAY_PARTITION variable=hist_out1 dim=1 complete
  	ap_uint<32>hist_out2[N];
  #pragma HLS ARRAY_PARTITION variable=hist_out2 dim=1 complete
  	unsigned int i,j=0;
  	XF_TNAME(XF_8UC3,XF_NPPC1)src1;
  	XF_TNAME(XF_8UC3,XF_NPPC1)src2;
  	XF_TNAME(XF_8UC3,XF_NPPC1)dst1;
  	XF_TNAME(XF_8UC3,XF_NPPC1)dst2;
  	ap_uint<8> value1[3];
  	ap_uint<8> value2[3];
  	int pos1,pos2;
  	for(i=0;i<N;i++)
  	{
  		hist_out1[i]=0;
  		hist_out2[i]=0;
  	}
  
  
  	for(i=0;i<ROWS;i++)
  	{
  		for(j=0;j<COLS;j+=2)
  		{
  #pragma HLS DEPENDENCE variable=src1 intra false
  #pragma HLS DEPENDENCE variable=src2 intra false
  
  #pragma HLS PIPELINE II=2
  			src1=_src.read(i*COLS+j);
  			src2=_src.read(i*COLS+j+1);
  			ExtractPixel(src1,value1);
  			ExtractPixel(src2,value2);
  			pos1=(int)value1[0];
  			pos2=(int)value2[0];
  			hist_out1[pos1]+=1;
  			hist_out2[pos2]+=1;
  			value1[0]=map[pos1];
  			value2[0]=map[pos2];
  			PackPixel(dst1,value1);
  			PackPixel(dst2,value2);
  			_dst.write(i*COLS+j,dst1);
  			_dst.write(i*COLS+j+1,dst2);
  		}
  	}
  	int count_total = 0, tmp_hist;
  	float scale;
  	for(int i=0;i<N;i++)
  	{
  #pragma HLS PIPELINE
  		tmp_hist=hist_out1[i]+hist_out2[i];
  		count_total += tmp_hist;
  		scale = count_total*255/ROWS/COLS;
  		scale=(scale-i)*0.01*filter+i;
  		if(scale < 16)scale = 16;
  		if(scale > 255)scale = 235;
  		map[i] =  ap_uint<8>  (scale);
  	}
  }
  
  template <int ROWS, int COLS>
  void xfrgb2ycrcb(xf::cv::Mat<XF_8UC3, ROWS, COLS,XF_NPPC1>& src,
                   xf::cv::Mat<XF_8UC3, ROWS, COLS,XF_NPPC1>& dst)
  {
  	XF_TNAME(XF_8UC3,XF_NPPC1)rgb_packed;
  	XF_TNAME(XF_8UC3,XF_NPPC1)ycrcb_packed;
  	ap_uint<8>rgb[3];
  	ap_uint<8>ycrcb[3];
  	unsigned int i,j=0;
  	for(i=0;i<ROWS;i++)
  	{
  		for(j=0;j<COLS;j++)
  		{
  #pragma HLS PIPELINE
  			rgb_packed=src.read(i*COLS+j);
  			ExtractPixel(rgb_packed,rgb);
  			ycrcb[0]=CalculateGRAY(rgb[0],rgb[1],rgb[2]);
  			ycrcb[1]=Calculate_CR(rgb[0],ycrcb[0]);
  			ycrcb[2]=Calculate_CB(rgb[2],ycrcb[0]);
  			PackPixel(ycrcb_packed,ycrcb);
  			dst.write(i*COLS+j,ycrcb_packed);
  		}
  	}
  }
  
  template<int ROWS,int COLS>
  void xfycrcb2rgb(xf::cv::Mat<XF_8UC3, ROWS, COLS,XF_NPPC1>& src,
          		 xf::cv::Mat<XF_8UC3, ROWS, COLS,XF_NPPC1>& dst)
  {
  	XF_TNAME(XF_8UC3,XF_NPPC1)rgb_packed;
  	XF_TNAME(XF_8UC3,XF_NPPC1)ycrcb_packed;
  	ap_uint<8>rgb[3];
  	ap_uint<8>ycrcb[3];
  	unsigned int i,j=0;
  	for(i=0;i<ROWS;i++)
  	{
  		for(j=0;j<COLS;j++)
  		{
  #pragma HLS PIPELINE
  			ycrcb_packed=src.read(i*COLS+j);
  			ExtractPixel(ycrcb_packed,ycrcb);
  			rgb[0]=Calculate_Ycrcb2R(ycrcb[0],ycrcb[1]);
  			rgb[1]=Calculate_Ycrcb2G(ycrcb[0],ycrcb[1],ycrcb[2]);
  			rgb[2]=Calculate_Ycrcb2B(ycrcb[0],ycrcb[2]);
  			PackPixel(rgb_packed,rgb);
  			dst.write(i*COLS+j,rgb_packed);
  		}
  	}
  }
  
  void contrastadj(hls::stream<ap_axiu<24,1,1,1>> &src_axi,hls::stream<ap_axiu<24,1,1,1>> &dst_axi,int adj)
  {
  
  #pragma HLS INTERFACE mode=s_axilite port=return
  #pragma HLS INTERFACE mode=s_axilite port=adj register
  
  #pragma HLS INTERFACE axis port=src_axi
  #pragma HLS INTERFACE axis port=dst_axi
  
  	xf::cv::Mat<XF_8UC3,IMG_MAX_HEIGHT, IMG_MAX_WIDTH, XF_NPPC1> img1;
  #pragma HLS STREAM depth=1920 type=fifo variable=img1
  	xf::cv::Mat<XF_8UC3,IMG_MAX_HEIGHT, IMG_MAX_WIDTH, XF_NPPC1> img2;
  #pragma HLS STREAM depth=1920 type=fifo variable=img2
  	xf::cv::Mat<XF_8UC3,IMG_MAX_HEIGHT, IMG_MAX_WIDTH, XF_NPPC1> img3;
  #pragma HLS STREAM depth=1920 type=fifo variable=img3
  	xf::cv::Mat<XF_8UC3,IMG_MAX_HEIGHT, IMG_MAX_WIDTH, XF_NPPC1> img4;
  #pragma HLS STREAM depth=1920 type=fifo variable=img4
  
  #pragma HLS dataflow
  
  // AXIvideoTest<IMG_MAX_HEIGHT,IMG_MAX_WIDTH>(src_axi,dst_axi);
   xf::cv::AXIvideo2xfMat<24,XF_8UC3,IMG_MAX_HEIGHT,IMG_MAX_WIDTH,XF_NPPC1>(src_axi, img1);
  	xfrgb2ycrcb<IMG_MAX_HEIGHT,IMG_MAX_WIDTH>(img1, img2);
  	dualAryEqualize<IMG_MAX_HEIGHT, IMG_MAX_WIDTH, 256>(img2, img3,adj);
     xfycrcb2rgb<IMG_MAX_HEIGHT,IMG_MAX_WIDTH>(img3, img4);
   xf::cv::xfMat2AXIvideo<24,XF_8UC3,IMG_MAX_HEIGHT,IMG_MAX_WIDTH,XF_NPPC1>(img4,dst_axi);
  }

这里进行数据统计的时候,我们一次处理了两个像素点。因为在一个时钟内,我们无法完成“hist_out1[pos1] += 1;”,即读一个ram内容,将其加一并写回。但可以在两个时钟周期,完成一个读写操作

工程路径
==========================================

.. csv-table:: 
  :header: "名称", "路径"
  :widths: 20, 20

  "vivado 工程","vivado/video_show"
  "HLS工程","vivado/contrastadj"
  "HLS工程","hls/mem2stream"
  "HLS工程","hls/stream2mem"
  "BOOT.bin文件","bootimage"

实验结果
==========================================

对比度由0至100由SDK动态调整,0为原图,100为对比度最高。

对比度为0时

.. image:: images/images5/image58.png
      
对比度为100时

.. image:: images/images5/image59.png
      
 


