读写XMl或YAMl文件
- XML中写入数据一般步骤
// 打开一个xml文件,
string filename = "my.xml";
FileStorage fs(filename, FileStorage::WRITE);
// xml数据存储在FileNode中
// xml中第一种数据类型为element squence 在写入时 []位起始位置标志, <<位写入操作符
fs << "strings" << "["; // text - string sequence
fs << "image1.jpg" << "Awesomeness" << "../data/baboon.jpg";
fs << "]";
// xml第二种数据类型位mapping 类似与 key-value的结构 通过访问key来访问value,{}标志着起始和最终位置
fs << "mapping" <<"{";
fs << "one" << 1 << "two" << 2 <<"}";
//写入矩阵例子
Mat R = Mat_<uchar>::eye(3, 3);
fs << "R" << R;
// 完成写入后要释放
fs.release();
cout<<"write done"<<endl;
- XML读数据一般步骤
//取出element squence 类型的例子,这里也可以使用>>运算符
FileNode s = fs["strings"];
if(s.type()!=FileNode::SEQ)
{
cerr<<"strings is not a sequence"<<endl;
return 1;
}
FileNodeIterator it=s.begin(), it_end = s.end();
for(;it!=it_end; it++)
{
cout<<(string) *it <<endl;
}
// 取出mapping数据类型例子
s = fs["mapping"];
cout<<"Two="<<(int) (s["two"])<<" "<<"one="<<(int)(s["one"])<<endl;
//取出矩阵数据 使用>>运算符
Mat G;
fs["R"] >> G;
- 自定义数据类型写入或读取xml文件
//定义存储在xml文件中自己的数据类型
class MyData
{
public:
MyData() : A(0), X(0), id()
{}
explicit MyData(int) : A(97), X(CV_PI), id("mydata1234")
{}
void write(FileStorage& fs) const //为该类定义的写函数
{
fs << "{" << "A" << A << "X" << X << "id" << id << "}";
}
void read(const FileNode& node) //该类的写函数
{
A = (int)node["A"];
X = (double)node["X"];
id = (string)node["id"];
}
public:
int A;
double X;
string id;
};
//FileNode中将会调用这个Write函数进行自定义数据的写入
static void write(FileStorage& fs, const std::string&, const MyData& x)
{
x.write(fs);
}
FileNode中将会调用这个read函数进行自定义数据的读入
static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()){
if(node.empty())
x = default_value;
else
x.read(node);
}
// 重新定义<<操作符 从而使得<<可以操作对象
static ostream& operator<<(ostream& out, const MyData& m)
{
out << "{ id = " << m.id << ", ";
out << "X = " << m.X << ", ";
out << "A = " << m.A << "}";
return out;
}
int main(int argc, char **argv)
{
string filename = "my.xml";
FileStorage fs(filename, FileStorage::WRITE);
MyData m(1);
fs << "Mydata" << m;
// 完成写入后要释放
fs.release();
cout<<"write done"<<endl;
cout<<endl<<"read"<<endl;
fs.open(filename, FileStorage::READ);
if(!fs.isOpened())
{
cerr<<"Failed to open"<<endl;
return 1;
}
// 将节点数据分别存储在矩阵和自定义类中
MyData data;
fs["Mydata"] >> data;
cout << "MyData = " << endl << data << endl << endl;
return 0;
}
Harris corner detector
图像几种典型特征
- edge
- corners(also known interesting points)
- blobs(also known regions of interests)
角点:两个边界的交点,代表了两个边界方向都发生,也就是该店具有很高的梯度值
Harris 检测的原理
[原理](https://www.cnblogs.com/mikewolf2002/p/3547436.html)
void cornerHarris_demo( int, void* )
{
int blockSize = 2;//扫描时候窗口的大小
int apertureSize = 3;// sobel算子
double k = 0.05;//权衡经验参数,一般在0.05到0.5之间
Mat dst = Mat::zeros( src.size(), CV_32FC1 );
cornerHarris( src_gray, dst, blockSize, apertureSize, k );
Mat dst_norm, dst_norm_scaled;
normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
// Scales, calculates absolute values, and converts the result to 8-bit.
convertScaleAbs( dst_norm, dst_norm_scaled );
for( int i = 0; i < dst_norm.rows ; i++ )
{
for( int j = 0; j < dst_norm.cols; j++ )
{
if( (int) dst_norm.at<float>(i,j) > thresh )
{
circle( dst_norm_scaled, Point(j,i), 5, Scalar(0), 2, 8, 0 );
}
}
}
namedWindow( corners_window );
imshow( corners_window, dst_norm_scaled );
}
这个函数应该升级版:
void cv::goodFeaturesToTrack ( InputArray image,
OutputArray corners,
int maxCorners,
double qualityLevel,
double minDistance,
InputArray mask = noArray(),
int blockSize = 3,
bool useHarrisDetector = false,
double k = 0.04
)
// image 输入图像
// corners 检测出的角点
// maxCorners 最大检测角点数量
// qualityLevel 角点质量评价阈值,低于该数值的会被忽略
// minDistance两个角点的最小距离
// Optional region of interest
// blockSize 窗口大小
// useHarrisDetector=true, 使用Harris corner 否则使用 Shi-Tomasi
// k Harris corner中k值