// rgb2hsv.h
// 2016/10/06 by marsee
//
#ifndef __RGB2HSV_H__
#define __RGB2HSV_H__
//#define HORIZONTAL_PIXEL_WIDTH 800
//#define VERTICAL_PIXEL_WIDTH 600
#define HORIZONTAL_PIXEL_WIDTH 640
#define VERTICAL_PIXEL_WIDTH 480
//#define HORIZONTAL_PIXEL_WIDTH 64
//#define VERTICAL_PIXEL_WIDTH 48
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
#endif
// rgb2hsv.cpp
// 2016/10/06 by marsee
//
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include "rgb2hsv.h"
#define MAG 8 // 小数点以下のビット幅
int rgb2hsv(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE axis port=ins
ap_axis<32,1,1,1> pix;
int r, g, b;
int h, s, v;
int max, min;
int hsv;
do{
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
ins >> pix;
}while(pix.user == 0);
loop_y: for(int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
loop_x: for(int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS UNROLL factor=2
#pragma HLS PIPELINE II=1
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = r; // 8倍
min = r;
}else if(r>=g && r>=b){ // r が最大
max = r;
if(g>=b)
min = b;
else
min = g;
}else if(g>=r && g>=b){ // g が最大
max = g;
if(r>=b)
min = b;
else
min = r;
}else{ // b が最大
max = b;
if(r>=g)
min = g;
else
min = r;
}
if(max-min == 0)
h = 0;
else if(max == r)
h = 60 * (((g-b)<<MAG)/(max-min)); // MAGビットシフトして精度を確保
else if(max == g)
h = 60 * (((b-r)<<MAG)/(max-min)) + (120<<MAG); // MAGビットシフトして精度を確保
else // if(max == b)
h = 60 * (((r-g)<<MAG)/(max-min)) + (240<<MAG); // MAGビットシフトして精度を確保
if(h < 0)
h += 360<<MAG;
h += 1<<(MAG-1); // +0.5、四捨五入
h >>= MAG; // 桁を戻す
if(max == 0)
s = 0;
else
s = (((max - min)<<MAG)/max) * 255; // MAGビットシフトして精度を確保
s += 1<<(MAG-1); // +0.5、四捨五入
s >>= MAG; // 桁を戻す
v = max;
hsv = (h&0x1ff)*65536 + (s&0xff)*256 + (v&0xff);
pix.data = hsv;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
pix.user = 1;
else
pix.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
pix.last = 1;
else
pix.last = 0;
outs << pix;
}
}
return(0);
}
// rgb2hsv_tb.cpp
// 2016/10/09
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>
#include "rgb2hsv.h"
#include "bmp_header.h"
#define BMP_FILE_NAME "road_1.bmp"
#define SQUARE_ERROR_LIMIT 4 // 2乗誤差のエラー限界、この数以上はエラーとする
#define H 0
#define S 1
#define V 2
int rgb2hsv(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);
int rgb2hsv_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, int *pixel_buf, int select_hsv);
int main(){
using namespace std;
hls::stream<ap_axis<32,1,1,1> > ins;
hls::stream<ap_axis<32,1,1,1> > ins_soft;
hls::stream<ap_axis<32,1,1,1> > outs;
hls::stream<ap_axis<32,1,1,1> > outs_soft;
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> vals;
ap_axis<32,1,1,1> vals_soft;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw, *fbmpwf;
int *rd_bmp, *hw_hsv, *sw_hsv;
int blue, green, red;
if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // BMP ファイル をオープン
fprintf(stderr, "Can't open test.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_hsv =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_hsv memory\n");
exit(1);
}
if ((sw_hsv =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate sw_hsv memory\n");
exit(1);
}
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
ins_soft << pix;
}
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
rgb2hsv(ins, outs);
rgb2hsv_soft(ins_soft, outs_soft);
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
cout << endl;
cout << "outs" << endl;
for(int j=0; j < bmpihr.biHeight; j++){
for(int i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<32> val = vals.data;
ap_int<32> val_soft = vals_soft.data;
hw_hsv[(j*bmpihr.biWidth)+i] = (int)val;
sw_hsv[(j*bmpihr.biWidth)+i] = (int)val_soft;
red = (rd_bmp[(j*bmpihr.biWidth)+i]>>16) & 0xff;
green = (rd_bmp[(j*bmpihr.biWidth)+i]>>8) & 0xff;
blue = rd_bmp[(j*bmpihr.biWidth)+i] & 0xff;
if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > SQUARE_ERROR_LIMIT || // v の2乗誤差が4よりも大きい
(double)pow((double)((val>>8)&0xff)-((val_soft>>8)&0xff),(double)2) > SQUARE_ERROR_LIMIT || // s の2乗誤差が4よりも大きい
(double)pow((double)((val>>16)&0x1ff)-((val_soft>>16)&0x1ff),(double)2) > SQUARE_ERROR_LIMIT){ // h の2乗誤差が4よりも大きい
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, Red = %d, Green = %d, Blue = %d, "
"HW_h = %d, HW_s = %d, HW_v = %d, SW_h = %d, SW_s = %d, SW_v = %d\n",
i, j, red, green, blue, (int)(val>>16)&0xff, (int)(val>>8)&0xff, (int)val&0xff,
(int)(val_soft>>16)&0xff, (int)(val_soft>>8)&0xff, (int)val_soft&0xff);
//return(1);
}
//if (vals.last)
//cout << "AXI-Stream is end" << endl;
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
if ((fbmpw=fopen("h_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open h_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, H);
if ((fbmpw=fopen("s_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open s_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, S);
if ((fbmpw=fopen("v_hw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open v_hw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, hw_hsv, V);
if ((fbmpw=fopen("h_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open h_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, H);
if ((fbmpw=fopen("s_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open s_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, S);
if ((fbmpw=fopen("v_sw.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open v_sw.bmp by binary write mode\n");
exit(1);
}
WriteBmpFile(fbmpw, bmpfhr, bmpihr, sw_hsv, V);
free(rd_bmp);
free(hw_hsv);
free(sw_hsv);
}
int rgb2hsv_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
ap_axis<32,1,1,1> pix;
int r, g, b;
float h, s;
int v;
int max, min;
int hsv;
do{
ins >> pix;
}while(pix.user == 0);
loop_y: for(int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
loop_x: for(int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if(!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
b = pix.data & 0xff;
g = (pix.data>>8) & 0xff;
r = (pix.data>>16) & 0xff;
// h と max, min を求める
if(r==g && g==b && r==b){
max = r;
min = r;
}else if(r>=g && r>=b){
max = r;
if(g>=b)
min = b;
else
min = g;
}else if(g>=r && g>=b){
max = g;
if(r>=b)
min = b;
else
min = r;
}else{ // b が最大
max = b;
if(r>=g)
min = g;
else
min = r;
}
if(max-min == 0)
h = 0.0;
else if(max == r)
h = 60.0 * ((float)(g-b)/(float)(max-min));
else if(max == g)
h = 60.0 * ((float)(b-r)/(float)(max-min)) + 120.0;
else // if(max == b)
h = 60.0 * ((float)(r-g)/(float)(max-min)) + 240.0;
if(h < 0)
h += 360.0;
if(max == 0)
s = 0.0;
else
s = (float)(max - min)/(float)max * 255.0;
v = max;
hsv = (((int)(h+0.5))&0x1ff)*65536 + (((int)(s+0.5))&0xff)*256 + (v&0xff); // h と s は四捨五入
pix.data = hsv;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
pix.user = 1;
else
pix.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
pix.last = 1;
else
pix.last = 0;
outs << pix;
}
}
return(0);
}
// SV のうちの1つをblue, green, redの値として同じ値をBMPファイルに書く
// H は S,V の値を255とした時の H の値に対する RGB の値を計算する
void WriteBmpFile(FILE *fbmpw, BITMAPFILEHEADER &bmpfhr, BITMAPINFOHEADER &bmpihr, int *pixel_buf, int select_hsv){
int h;
int sv;
int r, g, b;
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
switch(select_hsv){
case H:
h = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0x1ff;
if(h>=0 && h<60){
r = 255;
g = (int)(((float)h/60.0)*255.0+0.5);
b = 0;
}else if(h>=60 && h<120){
r = (int)(((120.0-(float)h)/60.0)*255+0.5);
g = 255;
b = 0;
}else if(h>=120 && h<180){
r = 0;
g = 255;
b = (int)((((float)h-120.0)/60.0)*255+0.5);
}else if(h>=180 && h<240){
r = 0;
g = (int)(((240.0-(float)h)/60.0)*255+0.5);
b = 255;
}else if(h>=240 && h<300){
r = (int)((((float)h-240.0)/60.0)*255+0.5);
g = 0;
b = 255;
}else{ // h>=300 && h<=360
r = 255;
g = 0;
b = (int)(((360.0-(float)h)/60.0)*255+0.5);
}
break;
case S:
sv = (pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
break;
default: // case V:
sv = pixel_buf[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
break;
}
if(select_hsv==S || select_hsv==V){
fputc(sv, fbmpw);
fputc(sv, fbmpw);
fputc(sv, fbmpw);
}else{
fputc(b, fbmpw);
fputc(g, fbmpw);
fputc(r, fbmpw);
}
}
}
fclose(fbmpw);
}
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |