通过实现一个基础算法,熟悉vivadoHLS操作步骤,同时理解串行转并行的思维
1.在for循环中加pipeline的同时,谨慎添加rewinding
vivado HLS实例----实现AWB
通过实现一个基础算法,熟悉vivadoHLS操作步骤,同时理解串行转并行的思维
一、AWB工程代码
1.ReadFile.h
#include<iostream>
#include<fstream>
#include <iomanip>
#include <ap_int.h>
#include <hls_stream.h>
using std::cerr;
using std::cout;
using std::setw;
using std::setfill;
using std::ifstream;
using namespace std;
//using namespace hls;
//typedef ap_uint<128> img_rgb;
//typedef stream<img_rgb> img_rgb_stream;
//hls::stream<my_uint128_t>
template <int N, typename Tn>
void ReadFilaeVec(char * fp, Tn &Img_rgb_stream)
{
int i;
int val;
ifstream fp_strmi(fp);//fp is file mode
if (!fp_strmi.is_open())
{
cerr << "Error!\n The file is not albe to open!\n";
}
else
{
for (i = 0; i < N; i++) // N= w*h*ch
{
fp_strmi >> val;
// *pOutBuf = val;
Img_rgb_stream << val;
// pOutBuf++;
}
}
fp_strmi.close();
//cout << setw(60) << setfill('-') << '----'<<'\n';
cout << "Read file successfully\n";
//cout << setw(60) << setfill('-') << '-----'<<'\n';
}
2.stream_awb_head.h
#include <ap_int.h>
#include <ap_fixed.h>
#include <hls_stream.h>
using namespace hls;
typedef ap_uint<10> img_rgb;
typedef stream<img_rgb> stream_rgb;
//stream_rgb in_rgb_stream;
//stream_rgb out_rgb_stream;
#define IMAGE_WIDTH 100
#define IMAGE_HEIGHT 100
#define IMAGE_CHANNEL 3
#define IMAGE_WINSIZE (IMAGE_WIDTH * IMAGE_HEIGHT)
#define IMAGE_SIZE (IMAGE_WINSIZE * IMAGE_CHANNEL)
#define W 35
#define I 23
typedef ap_ufixed<W,I> img_cef;
//ap_ufixed<W,I> img_cef = 0;
//img_rgb M = img_rgb(255);
//img_cef T = (img_cef)(256);
//
//img_cef g_coefr = (img_cef)(1);
//img_cef g_coefg = (img_cef)(1);
//img_cef g_coefb = (img_cef)(1);
typedef unsigned char U8;
void balance_white_top(stream_rgb &in_rgb_stream, stream_rgb &out_rgb_stream,
img_cef &g_kr,img_cef &g_kg,img_cef &g_kb);
//void balance_white_top(U8 img_r[IMAGE_WINSIZE], U8 img_g[IMAGE_WINSIZE], U8 img_b[IMAGE_WINSIZE]);
3.stream_awb_top.cpp
#include<fstream>
#include <iomanip>
#include<fstream>
#include<iostream>
#include <ap_fixed.h>
#include "stream_awb_head.h"
img_cef W_div = 1.0 / 3.0;
//img_cef coefr, coefg, coefb;
//static float W_div = 1.0 / 3.0;
img_rgb M = img_rgb(255);
img_cef T = (img_cef)(256);
img_cef g_coefr = (img_cef)(1);
img_cef g_coefg = (img_cef)(1);
img_cef g_coefb = (img_cef)(1);
void Addfunnction(img_rgb &val, img_cef coef, img_cef &K){
img_cef valNew;
//float K_img = 0;
img_rgb val_rgb = val;
K += val_rgb;
//更新像素
valNew = ((img_cef)(val_rgb) * coef);
val = (valNew >= T) ? M : (img_rgb)(valNew);
}
void balance_white_top(
stream_rgb &in_rgb_stream,
stream_rgb &out_rgb_stream,
img_cef &g_kr,img_cef &g_kg,img_cef &g_kb
) {
img_cef K = 0;
img_cef Kr = 0;
img_cef Kg = 0;
img_cef Kb = 0;
// img_cef coefr = g_coefr;
// img_cef coefg = g_coefg;
// img_cef coefb = g_coefb;
//U8 valr, valg, valb;
//img_rgb valr_r, valg_g, valb_b;
//img_rgb valNewr, valNewg, valNewb;
img_rgb valR;
img_rgb valG;
img_rgb valB;
img_rgb img_r[IMAGE_WINSIZE] = { 0 };
img_rgb img_g[IMAGE_WINSIZE] = { 0 };
img_rgb img_b[IMAGE_WINSIZE] = { 0 };
// g_kr = g_coefr;
loop1:
for (int i = 0; i < IMAGE_WINSIZE; i++) {
in_rgb_stream >> valR;
in_rgb_stream >> valG;
in_rgb_stream >> valB;
block1:
{
Addfunnction(valR, g_coefr, Kr);
Addfunnction(valG, g_coefg, Kg);
Addfunnction(valB, g_coefb, Kb);
}
img_r[i] = valR;
img_g[i] = valG;
img_b[i] = valB;
out_rgb_stream << img_r[i];
out_rgb_stream << img_g[i];
out_rgb_stream << img_b[i];
// out_rgb_stream << valR;
// out_rgb_stream << valG;
// out_rgb_stream << valB;
}
// K = Kr + Kg + Kb;
// K = K * W_div;
K = (Kr + Kg + Kb) * W_div;
//block2:
// {
g_coefr = K / Kr;
g_coefg = K / Kg;
g_coefb = K / Kb;
//}
// g_coefr = coefr;
// g_coefg = coefg;
// g_coefb = coefb;
// g_kr = g_coefr;
// g_kg = g_coefg;
// g_kb = g_coefb;
}
//第三版
//#include<fstream>
//#include <iomanip>
//#include<fstream>
//#include<iostream>
//
//#include "stream_awb_head.h"
//img_rgb M = 255;
//img_rgb T = 256;
//float coefr, coefg, coefb;
//static float W_div = 1.0 / 3.0;
//float g_coefr = 0;
//float g_coefg = 0;
//float g_coefb = 0;
//
//void Addfunnction(img_rgb *val, float coef, float *K){
// img_rgb valNew;
// // U8 *p = img;
// float K_img = 0;
loop2:
for (int i = 0; i < IMAGE_WINSIZE; i++) {
val = img[i];
// //更新像素
// valNew = *val * coef;
// *val = (valNew >= T) ? M : valNew;
//
// K_img += (float)(*val);
// //out_rgb << img[i];
}
// // // return K_img;
// *K = K_img;
//}
//
//void balance_white_top(stream_rgb &in_rgb_stream, stream_rgb &out_rgb_stream) {
// float K = 0;
// float Kr = 0;
// float Kg = 0;
// float Kb = 0;
//
// float coefr = g_coefr;
// float coefg = g_coefg;
// float coefb = g_coefb;
// //U8 valr, valg, valb;
// img_rgb valr_r, valg_g, valb_b;
//
// img_rgb valNewr, valNewg, valNewb;
//
//
// img_rgb valR;
// img_rgb valG;
// img_rgb valB;
// img_rgb img_r[IMAGE_WINSIZE] = { 0 };
// img_rgb img_g[IMAGE_WINSIZE] = { 0 };
// img_rgb img_b[IMAGE_WINSIZE] = { 0 };
//
//loop1:
// for (int i = 0; i < IMAGE_WINSIZE; i++) {
// in_rgb_stream >> valR;
// in_rgb_stream >> valG;
// in_rgb_stream >> valB;
//
img_r[i] = valR;
img_g[i] = valG;
img_b[i] = valB;
//
//
// block1:
// {
// Addfunnction(&valR, coefr, &Kr);
// Addfunnction(&valG, coefg, &Kg);
// Addfunnction(&valB, coefb, &Kb);
// }
// out_rgb_stream << valR;
// out_rgb_stream << valG;
// out_rgb_stream << valB;
//
// K = (Kr + Kg + Kb) * W_div;
//
// block2:
// {
// coefr = K / Kr;
// coefg = K / Kg;
// coefb = K / Kb;
// }
// g_coefr = coefr;
// g_coefg = coefg;
// g_coefb = coefb;
//
// }
//
//}
//第二版
//#include<fstream>
//#include <iomanip>
//#include<fstream>
//#include<iostream>
//
//#include "stream_awb_head.h"
//img_rgb M = 255;
//img_rgb T = 256;
//float coefr, coefg, coefb;
//static float W_div = 1.0 / 3.0;
//float g_coefr = 0;
//float g_coefg = 0;
//float g_coefb = 0;
//
//void Addfunnction(img_rgb img[IMAGE_WINSIZE], float coef, float *K){
// img_rgb val;
// img_rgb valNew;
// // U8 *p = img;
// float K_img = 0;
//loop2:
// for (int i = 0; i < IMAGE_WINSIZE; i++) {
// val = img[i];
// //更新像素
// valNew = val * coef;
// img[i] = (valNew >= T) ? M : valNew;
//
// K_img += (float)(val);
// //out_rgb << img[i];
// }
// // // return K_img;
// *K = K_img;
//}
//
//void balance_white_top(stream_rgb &in_rgb_stream, stream_rgb &out_rgb_stream) {
// float K = 0;
// float Kr = 0;
// float Kg = 0;
// float Kb = 0;
//
// float coefr = g_coefr;
// float coefg = g_coefg;
// float coefb = g_coefb;
// //U8 valr, valg, valb;
// img_rgb valr_r, valg_g, valb_b;
//
// img_rgb valNewr, valNewg, valNewb;
//
//
// img_rgb valR;
// img_rgb valG;
// img_rgb valB;
// img_rgb img_r[IMAGE_WINSIZE] = { 0 };
// img_rgb img_g[IMAGE_WINSIZE] = { 0 };
// img_rgb img_b[IMAGE_WINSIZE] = { 0 };
//
//loop1:
// for (int i = 0; i < IMAGE_WINSIZE; i++) {
// in_rgb_stream >> valR;
// in_rgb_stream >> valG;
// in_rgb_stream >> valB;
//
// img_r[i] = valR;
// img_g[i] = valG;
// img_b[i] = valB;
//
// }
//block1:
// {
// Addfunnction(img_r, coefr, &Kr);
// Addfunnction(img_g, coefg, &Kg);
// Addfunnction(img_b, coefb, &Kb);
// }
// K = (Kr + Kg + Kb) * W_div;
//
//block2:
// {
// coefr = K / Kr;
// coefg = K / Kg;
// coefb = K / Kb;
// }
// g_coefr = coefr;
// g_coefg = coefg;
// g_coefb = coefb;
// loop3:
// for (int i = 0; i < IMAGE_WINSIZE; i++) {
// out_rgb_stream << img_r[i];
// out_rgb_stream << img_g[i];
// out_rgb_stream << img_b[i];
// }
//
//}
//第一版
//void balance_white_top(stream_rgb &in_rgb_stream, stream_rgb &out_rgb_stream) {
// float K = 0;
// float Kr = 0;
// float Kg = 0;
// float Kb = 0;
//
// float coefr = g_coefr;
// float coefg = g_coefg;
// float coefb = g_coefb;
// //U8 valr, valg, valb;
// img_rgb valr_r, valg_g, valb_b;
//
// img_rgb valNewr, valNewg, valNewb;
//
//
// img_rgb valR ;
// img_rgb valG ;
// img_rgb valB ;
img_rgb img_r[IMAGE_WINSIZE] = { 0 };
img_rgb img_g[IMAGE_WINSIZE] = { 0 };
img_rgb img_b[IMAGE_WINSIZE] = { 0 };
//
// loop1:
// for (int i = 0; i < IMAGE_WINSIZE; i++) {
// in_rgb_stream >> valR;
// in_rgb_stream >> valG;
// in_rgb_stream >> valB;
//
Addfunnction(img_r, coefr, &Kr, &valr_r);
Addfunnction(img_g, coefg, &Kg, &valg_g);
Addfunnction(img_b, coefb, &Kb, &valb_b);
img_r[i] = valR;
img_g[i] = valG;
img_b[i] = valB;
//
// Kr += (float)(valR);
// Kg += (float)(valG);
// Kb += (float)(valB);
//
// //更新像素
// valNewr = valR * coefr;
// valNewg = valG * coefg;
// valNewb = valB * coefb;
//
// valr_r = (valNewr >= T) ? M : valNewr;
// valg_g = (valNewg >= T) ? M : valNewg;
// valb_b = (valNewb >= T) ? M : valNewb;
valr_r = (valNewr >= (img_rgb)(256)) ? (img_rgb)(255) : valNewr;
valg_g = (valNewg >= (img_rgb)(256)) ? (img_rgb)(255) : valNewg;
valb_b = (valNewb >= (img_rgb)(256)) ? (img_rgb)(255) : valNewb;
//
// out_rgb_stream << valr_r;
// out_rgb_stream << valg_g;
// out_rgb_stream << valb_b;
/*img_r[i] = valr_r;
img_g[i] = valg_g;
img_b[i] = valb_b;*/
// }
//
// K = (Kr + Kg + Kb) * W_div;
//
// block2:
// {
// coefr = K / Kr;
// coefg = K / Kg;
// coefb = K / Kb;
// }
// g_coefr = coefr;
// g_coefg = coefg;
// g_coefb = coefb;
//
//}
//float Addfunnction(img_rgb val, float coef, float *K,img_rgb *val_l){
//
// img_rgb valNew;
// int K_img = 0;
//
loop:
for (int i = 0; i < IMAGE_WINSIZE; i++) {
// //val = img[i];
// //更新像素
// valNew = val * coef;
// *val_l = (valNew >= T) ? M : valNew;
// //out_rgb_stream << val_l;
// K_img += (float)(val);
// //}
// // return K_img;
// *K = K_img;
//}
4.stream_awb_tb.cpp
#include <typeinfo>
#include <iostream>
#include <iomanip>
#include "ReadFile.h"
#include "stream_awb_head.h"
//#include <ap_uint.h>
//#include <hls_stream.h>
//#include <opencv2/opencv.hpp>
//using namespace cv;
int main(){
//U8 img[IMAGE_WINSIZE] = { 0 };
//img_rgb Ref[IMAGE_WINSIZE] = { 0 };
img_cef kr,kg,kb;
char *fa = "E:/HLS/vsproj/AWB_formal/AWB_formal/3chn.txt";
char *fp_ref = "E:/HLS/vsproj/AWB_formal/AWB_formal/3chn_ofter.txt";
//char *fp_ref = "C:/Users/11693/Desktop/ref_file.txt";
// typedef ap_uint<128> img_rgb;
stream_rgb in_img_rgb_stream;
stream_rgb out_rgb_stream1;
stream_rgb out_rgb_stream_full;
stream_rgb refimg_rgb_stream;
// stream
ReadFilaeVec<IMAGE_SIZE, stream_rgb>(fa, in_img_rgb_stream);
ReadFilaeVec<IMAGE_SIZE, stream_rgb>(fp_ref, refimg_rgb_stream);
unsigned int i = 0;
unsigned int errcnt = 0;
//第一帧
balance_white_top(in_img_rgb_stream, out_rgb_stream1, kr, kg, kb);
cout << "kr= " << kr << '\n';//探针
cout << "kg= " << kg << '\n';//探针
cout << "kb= " << kb << '\n';//探针
//第二帧
ReadFilaeVec<IMAGE_SIZE, stream_rgb>(fa, in_img_rgb_stream);
balance_white_top(in_img_rgb_stream, out_rgb_stream_full, kr, kg, kb);
cout << "kr= " << kr << '\n';//探针
cout << "kg= " << kg << '\n';//探针
cout << "kb= " << kb << '\n';//探针
//typedef ap_uint<32> img_rgb;
img_rgb Ref_val;
img_rgb out_val;
int Ref_val_U8;
int out_val_U8;
for (i = 0; i< IMAGE_SIZE; i++){
refimg_rgb_stream >> Ref_val;
out_rgb_stream_full >> out_val;
Ref_val_U8 = (int)(Ref_val);
out_val_U8 = (int)(out_val);
if (abs(Ref_val_U8 - out_val_U8) > 1.0 ){
errcnt++;
cout << "i= " << i << " ----------";
// cout << "img[1]= " << img[i] << " ----------";
cout << "out_val= " << out_val << " ----------";
cout << "Ref_val= " << Ref_val << '\n';
break;
}
}
// cout << "kr= " << kr << '\n'; //探针
// cout << "kg= " << kg << '\n';//探针
// cout << "kb= " << kb << '\n';//探针
if (errcnt>0){
cout << "Test with " << errcnt << " error";
// system("pause");
return 1;
}
else{
cout << "Test Pass";
// system("pause");
return 0;
}
}
二、添加Directive
在stream_awb_top.cpp文件中添加directive
loop1:
for (int i = 0; i < IMAGE_WINSIZE; i++) {
#pragma HLS PIPELINE
in_rgb_stream >> valR;
in_rgb_stream >> valG;
in_rgb_stream >> valB;
block1:
{
#pragma HLS ALLOCATION instances=Addfunction limit=3 function
Addfunnction(valR, g_coefr, Kr);
Addfunnction(valG, g_coefg, Kg);
Addfunnction(valB, g_coefb, Kb);
}
三、实例工程分析
1.在for循环中加pipeline的同时,谨慎添加rewinding
添加rewinding会导致全局变量失效,g_coefr、g_coefg、g_coefb不会随着Addfunnction函数调用发生改变
2.串行转并行。
stream_awb_top.cpp文件中第一版、第二版、第三版都是串行
当前一帧的像素值使用上一帧的更新的g_coefr、g_coefg、g_coefb参数值。舍弃第一帧,只用第一帧的像素值只用于更新g_coefr、g_coefg、g_coefb参数值。
3.最后波形图
总结
- HLS很重要的是串行转并行的思想