在vivado中某些IP核的配置中,需要使用COE(Coefficient)文件来传递参数,例如MATLAB自动生成FIR滤波器所需的滤波系数文件以及RAM中的初始化数据文件等。COE文件是一种ASCII文本文件,文件头部定义数据基数(Radix),可以时2、10或16。数据以向量的形式给出,向量以分号结尾,向量之间用逗号隔开。Vivado会解析COE文件格式,并在生成IP核时导出相关的MIF格式文件,用于行为级仿真。
本次小项目生成COE文件是为了配置Block Memory Generator IP核时使用,将数据写入COE文件,传递给IP核,在vivado的应用中使用。如何写coe文件与vivado具体的应用息息相关,本次应用是将png、jpg等常见的图片灰度化、二值化后,写入coe中,位宽是128bit。coe中以32个16进制数据为一组,每个16进制是4bit,32个即为128bit。
Matlab作为主流的算法平台与验证平台之一往往成为很多数据的重要来源,因此在matlab下生成coe文件是非常普遍的操作,例如使用matlab提供的一些文件操作函数如fprint和fclose。除此之外,python提供了扩展库Numpy,可以方便地对矩阵操作,利用python生成coe也是比较简便的。正在写qt的总结,此处使用qt写coe文件,也并不复杂。
memory_initialization_radix = 10;
memory_initialization_vector = 1,2,3,4,5,6,…,99
其中:
memory_initialization_radix 是数值格式
memory_initialization_vector 是初始化的数值向量,分别对应各个深度
结合我们的应用需求,数值格式为16,数值向量是32个16进制数为一组。
1.搭建界面,简单布局
选择图片弹出文件对话框,选择将要生成coe的图片;QtextEdit用来打印当前状态,与用户做一些简单交互;clearBox用来清除状态提示框。
2.初始化Init()
初始化成员变量,打印当前状态,连接按钮信号和对应的槽。由于我的应用中只对应三种分辨率的图片,分别是“25601600”、“20481080”、“1024*768”。因此用户输入其他分辨率的图片将会提示输入不正确,程序不做任何处理。
3.槽函数
clearBox按钮的槽函数直接将edit清除就可以。选择图片的按钮则是要,打开文件选择框,用户选择标准图片后,对图片进行灰度化,二值化,然后移位处理,最后写成coe文件。
首先,通过用户点击路径“获取”图片对象
QString fileName = QFileDialog::getOpenFileName(this,"Seclect img","F:\\");
if(fileName.isEmpty())
{
return;
}
QFileInfo fileInfo=QFileInfo(fileName);//获取文件信息
QImage img = QImage(fileName);
然后,使用QImage方法,对其进行灰度化
img=img.convertToFormat(QImage::Format_Grayscale8);//将png、jpg转换成8位灰度 这个算法是Qt内部实现的
然后,保存灰度化数据
savePix = img.bits(); //保存灰度化数据
然后计算二值化阈值,采用求平均的方法(结合代码查看)
int threshold_value=average(savePix,height*width);
然后,根据灰度化数据计算并保存二值化数据
for(int j=0;j<width*height;j++)//计算保存二值化数据
{
if(savePix[j]>threshold_value)
{tempbin[j]=0;}
else
{tempbin[j]=1;}
}
然后,将二值化数据移位处理成1个16进制数的4bit分别代表4个像素数据
for (int i = 0;i<width*height/4;i++ )
for(int j = 0;j<4;j++)
{
if(j==0)
{
temphex = tempbin[i*4];
}
else
{
temphex=(temphex<<1)+tempbin[i*4+j];
}
}
dataBuf[i]=temphex;
最后,调用写coe文件函数,将dataBuf中的数据写到coe中
bool Widget::writeCoe7000(QFileInfo info)
{
QString str=info.baseName();
str.append(".coe");
FILE *fp= fopen(str.toLatin1(),"w");
fprintf(fp, "memory_initialization_radix = 16;\n");
fprintf(fp, "memory_initialization_vector = \n");
for(int q=0;q<6144;q++)
{
for (int i =0;i<32 ;i++ )
{
{fprintf(fp, "%x", dataBuf[q*32+i]);}
}
fprintf(fp, ",\n");//每128bit,即每32个16进制数据写一个逗号加换行
}
fclose(fp);
return true;
}
希望总结和整理的部分是,图片二值化的方法,移位处理的方法,使用c++的方式进行文件的写入操作,简单程序的快速搭建思路;需要澄清的是,由于下位机设备特殊,因此不同分辨率的图片做了不同调整,此处略过即可。
main
#include "widget.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
Init();
}
Widget::~Widget()
{
delete ui;
}
void Widget::Init()
{
//init 成员变量
height = 0;
width = 0;
temphex = 0;
currentState("请选择标准图片2560*1600或2048*1080或1024*768"); //调用显示当前状态函数
currentState("请注意在使用时将最后一个逗号改为分号才能进入vivado使用"); //调用显示当前状态函数
//关联按钮信号与槽
connect(ui->clearBtn,SIGNAL(clicked(bool)),ui->textEdit,SLOT(clear()));
connect(ui->selBtn,SIGNAL(clicked(bool)),this,SLOT(doProcessSelBtn(bool)));
}
void Widget::currentState(QString str)
{
dataTime = QDateTime::currentDateTime();
dataStr= dataTime.toString( "yyyy年MM月dd日 hh:mm:ss");
dataStr.append(": ");
dataStr.append(str);
ui->textEdit->append(dataStr); //设置显示当前系统时间
dataStr.clear();
}
int Widget::average(uchar *ary, int len)
{
int sum=0;
for (int i=0;i<len;i++)
{
sum+=ary[i];
}
return sum/len;
}
void Widget::doProcessSelBtn(bool)
{
QString fileName = QFileDialog::getOpenFileName(this,"Seclect img","F:\\");
if(fileName.isEmpty())
{
return;
}
QFileInfo fileInfo=QFileInfo(fileName);//获取文件信息
QImage img = QImage(fileName);
width = img.width();
height = img.height();
qDebug()<<width<<height;
if((width!=2560)||(height!=1600))//不是DLP9000X
{
if((width!=2048)||(height!=1080))//不是DLP9500
{
if((width!=1024)||(height!=768))//不是DLP7000
{
currentState("此次输入无效,请选择标准图片输入");
return;
}
}
}
//判断过程结束,是标准图片
img=img.convertToFormat(QImage::Format_Grayscale8);//将png、jpg转换成8位灰度 这个算法是Qt内部实现的
savePix = img.bits(); //保存灰度化数据
tempbin = new int[height*width];//二值化数据存储空间
int threshold_value=average(savePix,height*width);//二值化算法(求平均)
for(int j=0;j<width*height;j++)//计算保存二值化数据
{
//这里01赋值已经验证过
if(savePix[j]>threshold_value)
{tempbin[j]=0;}
else
{tempbin[j]=1;}
}
dataBuf = new char[width*height/4];//使用一个数组元素保存四个像素数据。(一个16进制为4位二进制)
for (int i = 0;i<width*height/4;i++ )//1024000=2560*1600/4,相当于每一个databuf中保存
{
for(int j = 0;j<4;j++)
{
if(j==0)
{
temphex = tempbin[i*4];
}
else
{
temphex=(temphex<<1)+tempbin[i*4+j];//已经验证!!!
}
}
dataBuf[i]=temphex;
}
if(width==2560)//9000X
{
if(writeCoe9000x(fileInfo))
{
currentState("DLP9000X---COE文件已生成,请在软件目录下查看!");
}
else
{
currentState("DLP9000X---COE文件生成失败,请重新输入!");
}
}
if(width==2048)//9500
{
if(writeCoe9500(fileInfo))
{
currentState("DLP9500---COE文件已生成,请在软件目录下查看!");
}
else
{
currentState("DLP9500---COE文件生成失败,请重新输入!");
}
}
if(width==1024)//7000
{
if(writeCoe7000(fileInfo))
{
currentState("DLP7000---COE文件已生成,请在软件目录下查看!");
}
else
{
currentState("DLP7000---COE文件生成失败,请重新输入!");
}
}
delete [] tempbin;
delete [] dataBuf;
}
bool Widget::writeCoe7000(QFileInfo info)
{
QString str=info.baseName();
str.append(".coe");
FILE *fp= fopen(str.toLatin1(),"w");
fprintf(fp, "memory_initialization_radix = 16;\n");
fprintf(fp, "memory_initialization_vector = \n");
/*说明:
coe文件一个数据的位宽是128bit,也就是需要32个16进制数,即32*4bit = 128。
对于7000来说,一行1024个数据,只有一组数据通道,256个16进制数据为一行。
一帧1024*768的图片总共有1024*768/4个数据保存,而1024*768/4 = 32*6144(32代表一行coe数据,6144代表一共这么多行)
另外每一行,每128bit,每32个16进制数都要写一个逗号。
*/
for(int q=0;q<6144;q++)
{
for (int i =0;i<32 ;i++ )
{
{fprintf(fp, "%x", dataBuf[q*32+i]);}
}
fprintf(fp, ",\n");//每128bit,即每32个16进制数据写一个逗号加换行
}
fclose(fp);
return true;
}
bool Widget::writeCoe9500(QFileInfo info)
{
QString str=info.baseName();
QString str2=info.baseName();
str.append("_ab.coe");
str2.append("_cd.coe");
FILE *fp= fopen(str.toLatin1(),"w");
FILE *fp2= fopen(str2.toLatin1(),"w");
fprintf(fp, "memory_initialization_radix = 16;\n");
fprintf(fp, "memory_initialization_vector = \n");
fprintf(fp2, "memory_initialization_radix = 16;\n");
fprintf(fp2, "memory_initialization_vector = \n");
/*说明:
coe文件一个数据的位宽是128bit,也就是需要32个16进制数,即32*4bit = 128。
对于9500来说,一行2048个数据,也就是有512个16进制数保存一行数据。那么前256个数据属于是ab通道,后256个数据是cd通道。
一帧2048*1080的图片总共有2048*1080/4个数据保存,而2048*1080/4 = 32*17280(32代表一行coe数据,17280代表一共这么多行)
另外每一行,每128bit,每32个16进制数都要写一个逗号。
*/
for(int q=0;q<17280;q++)
{
for (int i =0;i<32 ;i++ )
{
if((q*32+i)%512<256)//前320个属于ab通道
{fprintf(fp, "%x", dataBuf[q*32+i]);}
else
{fprintf(fp2, "%x", dataBuf[q*32+i]);}
}
if((q*32+31)%512<256)//每128bit,即每32个16进制数据写一个逗号
{fprintf(fp, ",\n");}
else
{fprintf(fp2, ",\n");}
}
fclose(fp);
fclose(fp2);
return true;
}
bool Widget::writeCoe9000x(QFileInfo info)
{
QString str=info.baseName();
QString str2=info.baseName();
str.append("_ab.coe");
str2.append("_cd.coe");
FILE *fp= fopen(str.toLatin1(),"w");
FILE *fp2= fopen(str2.toLatin1(),"w");
fprintf(fp, "memory_initialization_radix = 16;\n");
fprintf(fp, "memory_initialization_vector = \n");
fprintf(fp2, "memory_initialization_radix = 16;\n");
fprintf(fp2, "memory_initialization_vector = \n");
/*说明:
coe文件一个数据的位宽是128bit,也就是需要32个16进制数,即32*4bit = 128。
对于9000X来说,一行2560个数据,也就是有640个16进制数保存一行数据。那么前320个数据属于是ab通道,后320个数据是cd通道。
一帧2560*1600的图片总共有2560*1600/4个数据保存,而2560*1600/4 = 32*32000(32代表一行coe数据,32000代表一共这么多行)
另外每一行,每128bit,每32个16进制数都要写一个逗号。
*/
for(int q=0;q<32000;q++)
{
for (int i =0;i<32 ;i++ )
{
if((q*32+i)%640<320)//前320个属于ab通道
{fprintf(fp, "%x", dataBuf[q*32+i]);}
else
{fprintf(fp2, "%x", dataBuf[q*32+i]);}
}
if((q*32+31)%640<320)//每128bit,即每32个16进制数据写一个逗号
{fprintf(fp, ",\n");}
else
{fprintf(fp2, ",\n");}
}
fclose(fp);
fclose(fp2);
return true;
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void Init();//初始化成员变量
void currentState(QString str);//显示当前时间戳加状态信息
int average(uchar *ary, int len);//计算二值化阈值
private slots:
void doProcessSelBtn(bool);
bool writeCoe7000(QFileInfo info);
bool writeCoe9500(QFileInfo info);
bool writeCoe9000x(QFileInfo info);
private:
Ui::Widget *ui;
QDateTime dataTime;//当前时间
QString dataStr;//text字符串
int height;//图片高
int width;//图片宽
int *tempbin;//保存一帧图片的二值化数据
uchar *savePix;//保存一帧图片的灰度化数据(8bit)
char *dataBuf ;//一个数组元素对应四个像素的二值化数据,即使用一个16进制代表四位二进制。
uchar temphex;
};
#endif // WIDGET_H