0%

2019-10-25随记

图像文件序列按序重命名编号 - std::glob && std::imwrite

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
int extractId(String a)
{
string a_ = a;
string src_ = "D:\\theThirdYear\\RM\\task1\\imageDataset\\";
int pos_a = a_.find(src_);
int n = src_.size();
a_ = a_.erase(pos_a, n);

string tail = ".jpg";
pos_a = a_.find(tail);
n = src_.size();
a_ = a_.erase(pos_a, n);

stringstream ss;
int A;
ss << a_;
ss >> A;

return A;
}

int main()
{
Mat image;
String src = "D:\\theThirdYear\\RM\\task1\\imageDataset\\";
String dst = "D:/theThirdYear/RM/task1/image/";

vector<String> names;
char name[10];
glob(src, names, false);
sort(names.begin(), names.end(),cmp);

for (int i = 0; i < names.size(); i++)
{
image = imread(names[i]);
if (image.data != NULL)
{
sprintf_s(name, "%04d.jpg", i);
imwrite(dst + name, image);
cout << name << endl;
}
else {
cout << "end of reading" << endl;
}

}
return 0;
}

string字符串中删去指定字符/字符串 - string::find && string::erase

1
2
3
4
5
string str;
string target;
int pos = str.find(target);
n = target.size();
str = str.erase(pos,n);

字符串和数字的相互转化 - stringstream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <sstream>

// 字符串->数字
string str = "123";
int id;

stringstream ss;
ss << str;
ss >> id;

// 数字->字符串
int id = 123;
string str;

stringstream ss;
ss << id;
ss >> str;

在图片上打印帧数 - cv::putText

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Mat putFrame(Mat &image, int frame)
{
Mat img = image;
// 输出文本字符串
char id[10];
sprintf_s(id, "%04d", frame++);
string text = "Frame: ";
text = text + id;
// 设置文本参数
int font_face = FONT_HERSHEY_COMPLEX;
double font_scale = 1;
int thickness = 2;
int baseline;
// 获取文本框长宽
Size text_size = getTextSize(text, font_face, font_scale, thickness, &baseline);
Point origin;
origin.x = 0;
origin.y = text_size.height;
putText(img, text, origin, font_face, font_scale, Scalar(255, 255, 255), thickness, 8, 0);
return img;
}

读入视频/图像序列 - cv::VideoCapture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::string frame_file = "your/frame_file/path/%d.jpg";
cv::VideoCapture Sequence(frame_file);
if (!Sequence.isOpened())
std::cerr << "Failed to open image dataset" << std::endl;
while(1)
{
Sequence >> img;
if (img.empty())
{
std::cout << "End of Sequence" << std::endl;
break;
}
// 图片处理
}

给定范围内图像二值化 - cv::inRange

1
cv::inRange(hsv_img, cv::Scalar(hmin, smin, vmin), cv::Scalar(hmax, smax, vmax), bin_img);

生成滚动条控制参数变化 - cv::createTrackbar

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 滚动条参数,初始值为0/360,反馈滚动条上的数值
int hmin = 0;
int hmax = 360;
int smin = 0;
int smax = 255;
int vmin = 0;
int vmax = 255;
// 滚动条参数最大值,最小值默认为0
int hmin_max = 360;
int hmax_max = 360;
int smin_max = 255;
int smax_max = 255;
int vmin_max = 255;
int vmax_max = 255;

// 设置为全局变量一边在子函数中的使用
Mat hsv_img;
Mat bin_img;

void on_Trackbar(int, void*)
{
cv::inRange(hsv_img, cv::Scalar(hmin, smin, vmin), cv::Scalar(hmax, smax, vmax), bin_img);
cv::imshow("bin_img", bin_img);
}

int main()
{
cv::namedWindow("Trackbar", 1);
cv::createTrackbar("hmin", "Trackbar", &hmin, hmin_max, on_Trackbar);
cv::createTrackbar("hmax", "Trackbar", &hmax, hmax_max, on_Trackbar);
cv::createTrackbar("smin", "Trackbar", &smin, smin_max, on_Trackbar);
cv::createTrackbar("smax", "Trackbar", &smax, smax_max, on_Trackbar);
cv::createTrackbar("vmin", "Trackbar", &vmin, vmin_max, on_Trackbar);
cv::createTrackbar("vmax", "Trackbar", &vmax, vmax_max, on_Trackbar);

while(1)
{
Sequence >> img;
if (img.empty())
{
std::cout << "End of Sequence" << std::endl;
break;
}
hsv_img = cv::Mat(img.size(), img.type());
cv::cvtColor(img, hsv_img, CV_BGR2HSV);

//结果在回调函数中显示
on_Trackbar(hmin, 0);
on_Trackbar(hmax, 0);
on_Trackbar(smin, 0);
on_Trackbar(smax, 0);
on_Trackbar(vmin, 0);
on_Trackbar(vmax, 0);

cv::waitKey();
}
}

寻找列表中的最小值和最大值 - std::minmax()

  该函数返回一个pair,该pairfirst元素值为最小值(第一次出现的),second元素的值为最大值(第一次出现的)。

1
auto it = minmax([1,2,3,4,5]);

旋转矩形类 - cv::RotatedRect(const Point2f& center, const Size2f& size, float angle)

  • center : 矩形中心坐标
  • size: 矩形长宽
  • angle:从水平轴开始的顺时针旋转角度

轮廓提取函数 - void cv::findContours

函数原型
1
2
3
4
findContours( InputOutputArray image, OutputArrayOfArrays contours,
              OutputArray hierarchy, int mode,  
              int method, Point offset=Point()
); 
  • image: 单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;
  • contours: 定义为vector<vector<Point>> contours,是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。
  • hierarchy: 定义为 vector<Vec4i> hierarchy,也是一个向量,向量内每个元素保存了一个包含4个int整型的数组。向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。
      hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~ hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~ hierarchy[i][3]的相应位被设置为默认值-1。
  • mode: 定义轮廓的检索模式:
    • CV_RETR_EXTERNAL: 只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略。
    • CV_RETR_LIST: 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1。
    • CV_RETR_CCOMP: 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层。两个等级关系:顶层为连通域的外围边界,次层为孔的内层边界。
    • CV_RETR_TREE: 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
  • method: 定义轮廓的近似方法:
    • CV_CHAIN_APPROX_NONE: 保存物体边界上所有连续的轮廓点到contours向量内
    • CV_CHAIN_APPROX_SIMPLE: 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留
    • CV_CHAIN_APPROX_TC89_L1CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
  • Point: 偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,并且Point还可以是负值

轮廓绘制函数 - void cv::drawContours

函数原型
1
2
3
4
5
6
7
8
9
10
11
12
void drawContours
(
InputOutputArray image,
InputArrayOfArrays contours,
int contourIdx,
const Scalar& color,
int thickness = 1
int lineType = 8
InputArray hierarchy = noArray(),
int maxLevel = INT_MAX,                                       
Point offset = Point()
)
  • image: 要绘制轮廓的图像
  • contours: 所有输入的轮廓,每个轮廓被保存成一个point向量
  • contourIdx: 指定要绘制轮廓的编号,如果是负数,则绘制所有的轮廓
  • color: 绘制轮廓所用的颜色
  • thickness: 绘制轮廓的线的粗细,如果是负数,则轮廓内部被填充
  • lineType: 绘制轮廓的线的连通性
  • hierarchy: 关于层级的可选参数,只有绘制部分轮廓时才会用到
  • maxLevel: 绘制轮廓的最高级别,这个参数只有hierarchy有效的时候才有效
    • maxLevel=0,绘制与输入轮廓属于同一等级的所有轮廓即输入轮廓和与其相邻的轮廓
    • maxLevel=1, 绘制与输入轮廓同一等级的所有轮廓与其子节点
    • maxLevel=2,绘制与输入轮廓同一等级的所有轮廓与其子节点以及子节点的子节点
  • offset: 偏移量

轮廓的最小外接矩形函数 - Rect cv::boundingRect( InputArray array )

  • InputArray array: 一般为findContours函数查找的轮廓,包含轮廓的点集或者Mat;
  • 返回值为最小外接矩形的Rect,即左上点与矩形的宽度和高度;

返回指定形状和尺寸的结构元素 - Mat cv::getStructuringElement

函数原型:
1
2
3
Mat getStructuringElement(
int shape, Size esize, Point anchor = Point(-1, -1)
);
  • shape: 表示内核的形状
    • MORPH_RECT: 矩形
    • MORPH_CROSS: 交叉形
    • MORPH_ELLIPSE: 椭圆形
  • esize & anchor: 内核的尺寸以及锚点的位置,默认值Point(-1,-1)表示位于中心。
  • 一般在调用膨胀/腐蚀函数dilateerode之前,先定义一个Mat类型的变量来获得该函数的返回值,作为膨胀/腐蚀函数的膨胀操作内核输入。

膨胀函数 - cv::dilate()

使用像素邻域内的局部极大运算符来膨胀一张图片,从src输入, 由dst输出。

函数原型
1
2
3
4
5
6
7
8
9
void dilate(
InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor=Point(-1,-1),
int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue()
);
  • src: 输入源图像,Mat类即可
  • dst: 和源图像有相同尺寸和类型的目标图像
  • kernel: 膨胀操作的内核,当为NULL时,表示的是使用参考点位于中心$3\times 3$的核。一般使用函数Mat getStructuringElement配合这个参数使用。
  • anchor: 锚点位置,默认值表示位于中心
  • iterations: 迭代使用dilate()函数的次数,默认为1次
  • borderType: 用于推断图像外部像素的某种边界模式,有默认值,可以不考虑
  • borderValue: 当边界为常数时的边界值,有默认值,一般不去考虑
  • 使用膨胀函数,一般只需要填前面三个参数,后面四个都有默认值。

腐蚀函数 - cv::erode()

使用像素邻域内的局部极小运算符来腐蚀一张图片,从src输入, 由dst输出。

函数原型
1
2
3
4
5
6
7
8
9
void erode(
InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor=Point(-1,-1),
int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue()
);