学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为2822字,预计阅读8分钟
特效显示完结篇
今天这篇是使用OpenCV实现特效显示的最后一篇,主要是看看中间扩张和栅格显示。文章的最后我会把这一系列的源码放到GithHub上。
实现效果
上图中可以看到,左边两张图片是中间扩张的显示,分析是垂直方向和水平方向,右边的两张为栅格显示,也是通过水平和垂直方向设置。接下来就来看看这两种方式怎么实现的。
中间扩张显示
微卡智享
实现思路
# | 思路 |
---|---|
1 | 将图像分为两部分,将中间分界处显示在屏幕中央 |
2 | 从屏幕中央开始按设定的方向开始两边扫描 |
3 | 最后将图像完整的显示在屏幕上 |
核心代码
//中间扩张显示
//参数:src 源图像,
// width 图像宽度
// height 图像长度
// direction 方向 0-上下扩张 1-左右扩张
void midexpandshow(Mat src, int width, int height, int direction)
{
Mat dst = Mat(src.size(), CV_8UC3);
if (direction == 0) {
setshowwindow(src, "midexpandshow0", 1, 100);
//上下方向扩张
for (int i = 1; i < height / 2; ++i) {
src(Rect(0, height / 2 - i, width, i))
.copyTo(dst(Rect(0, height / 2 - i, width, i)));
src(Rect(0, height / 2, width, i))
.copyTo(dst(Rect(0, height / 2, width, i)));
imshow("midexpandshow0", dst);
waitKey(1);
}
}
else {
setshowwindow(src, "midexpandshow1", src.cols + 1, 100);
//左右方向扩张
for (int i = 1; i < width / 2; ++i) {
src(Rect(width / 2 - i, 0, i, height))
.copyTo(dst(Rect(width / 2 - i, 0, i, height)));
src(Rect(width / 2, 0, i, height))
.copyTo(dst(Rect(width / 2, 0, i, height)));
imshow("midexpandshow1", dst);
waitKey(1);
}
}
waitKey(0);
}
线程调用
//中间扩张显示
future<void> ftmidexpand0 = async(launch::async, midexpandshow, src, src.cols, src.rows, 0);
future<void> ftmidexpand1 = async(launch::async, midexpandshow, src, src.cols, src.rows, 1);
栅格显示
微卡智享
实现思路
# | 思路 |
---|---|
1 | 设置一个栅格的宽度,将图像分为若干行 |
2 | 将奇数行组成一组,偶数行组成一组 |
3 | 显示奇数行时水平方向为从右到左,垂直方向是从上到下 |
4 | 显示偶数行时水平方向为从左到右,垂直方向是从下到上 |
核心代码
//栅条特效
//参数 src 图像源
// width 图像宽度
// height 图像高度
// gridwidth 每个栅格宽度
// direction 方向 0-水平方向 1-垂直方向
void gridshow(Mat src, int width, int height, int gridwidth, int direction)
{
Mat dst = Mat(src.size(), CV_8UC3);
if (direction == 0) {
setshowwindow(src, "gridshow0", src.cols * 2 + 1, 100);
for (int i = 1; i < width + 1; i = i + gridwidth) {
//当I等于源图像宽度时,说明栅条全部遍历完成,直接显示原图像
if (i == width) {
cout << "over" << endl;
src.copyTo(dst);
imshow("gridshow0", dst);
break;
}
if (i > width - gridwidth) i = width - gridwidth;
for (int j = 0; j < height; j = j + 2 * gridwidth) {
if (j > height - 2 * gridwidth) j = height - 2 * gridwidth;
//奇数行从右往左
src(Rect(0, j, i, gridwidth))
.copyTo(dst(Rect(width - i, j, i, gridwidth)));
//偶数行从左往右
int k = j + gridwidth;
src(Rect(width - i, k, i, gridwidth))
.copyTo(dst(Rect(0, k, i, gridwidth)));
imshow("gridshow0", dst);
waitKey(1);
}
}
}
else {
setshowwindow(src, "gridshow1", src.cols * 3 + 1, 100);
for (int i = 1; i < height + 1; i = i + gridwidth) {
//当I等于源图像宽度时,说明栅条全部遍历完成,直接显示原图像
if (i == height) {
cout << "over" << endl;
src.copyTo(dst);
imshow("gridshow1", dst);
break;
}
if (i > height - gridwidth) i = height - gridwidth;
for (int j = 0; j < width; j = j + 2 * gridwidth) {
if (j > width - 2 * gridwidth) j = width - 2 * gridwidth;
//奇数列从上往下
src(Rect(j, height - i, gridwidth, i))
.copyTo(dst(Rect(j, 0, gridwidth, i)));
//偶数列从下往上
int k = j + gridwidth;
src(Rect(k, 0, gridwidth, i))
.copyTo(dst(Rect(k, height - i, gridwidth, i)));
imshow("gridshow1", dst);
waitKey(1);
}
}
}
waitKey(0);
}
线程调用
//栅格显示
future<void> ftgridshow0 = async(launch::async, gridshow, src, src.cols, src.rows, 18, 0);
future<void> ftgridshow1 = async(launch::async, gridshow, src, src.cols, src.rows, 18, 1);
代码地址
https://github.com/Vaccae/OpenCVImageEffect.git
完
扫描二维码
获取更多精彩
微卡智享
「 往期文章 」