当前位置: 首页 > news >正文

网站开发的技术可行性怎么写做网站还有开发文档吗

网站开发的技术可行性怎么写,做网站还有开发文档吗,软件公司名称推荐,深圳个人做网站博客主页:【夜泉_ly】 本文专栏:【暂无】 欢迎点赞👍收藏⭐关注❤️ 目录 cv::MatdistanceTransform获得SDF 本文的目标, 是简单学习并使用OpenCV的相关函数, 并获得QImage的SDF(Signed Distance Field 有向距离场) 至…

博客主页:【夜泉_ly】
本文专栏:【暂无】
欢迎点赞👍收藏⭐关注❤️

在这里插入图片描述

目录

  • cv::Mat
  • distanceTransform
  • 获得SDF

本文的目标,
是简单学习并使用OpenCV的相关函数,
并获得QImage的SDF(Signed Distance Field 有向距离场)
至于我要用QImage的SDF来做什么,嗯,以后再说。

cv::Mat

这个可以理解为OpenCV的QImage,嗯。
简单看看就行。

首先,Mat是可以存QImage并显示的。
其次,Mat是可以手搓的。
我们先手搓一个白底的黑色正方形,看看效果:

void Widget::on_pushButton_clicked()
{cv::Mat testMat(201, 201, CV_8UC1);for(int i = 0; i <= 200; i++){for(int j = 0; j <= 200; j++){// testMat[i][j] = 0; 这不行呢if((90 < i && i < 110) && (90 < j && j < 110)) {testMat.at<uchar>(i, j) = 0;   // 0   - 黑} else {testMat.at<uchar>(i, j) = 255; // 255 - 白}}}cv::imshow("testMat", testMat);
}

在这里插入图片描述
CV_8UC1 ,表示 8 位单通道,即灰度图,这个之后会用。

先试试把QImage转为灰度图:

cv::Mat image_to_CV_8UC1(const QImage& image){int w = image.width(),h = image.height();cv::Mat mat(w, h, CV_8UC1);for(int i = 0; i < w; i++){for(int j = 0; j < h; j++){ // 注: 只能设为全0,或全1mat.at<uchar>(i, j) = (image.pixelColor(i, j).alpha() == 0) ? 0 : 255;}}if(mat.empty()) return mat;cv::imshow("image", mat);return mat;
}

跑一下,发现图像被逆时针转了九十度。
cv::Mat 的这个构造,传的分别是 ( 行, 列, 类型)
QImage 的 width 是宽, height 是高,刚好反了:
在这里插入图片描述
改了顺序过后就对了:

cv::Mat image_to_CV_8UC1(const QImage& image){int r = image.height(), c = image.width();cv::Mat mat(r, c, CV_8UC1);for(int i = 0; i < r; i++){for(int j = 0; j < c; j++){ // 注意下面 image 是 (j, i)mat.at<uchar>(i, j) = (image.pixelColor(j, i).alpha() == 0) ? 0 : 255;}}if(mat.empty()) return mat;cv::imshow("image", mat);return mat;
}

在这里插入图片描述
再来试试翻转,我们需要把0变非0,把非0变0,
这个用条件判断加赋值有点慢,
不过,OpenCV 有现成的函数 bitwise_not :

void Widget::on_pushButton_2_clicked(bool checked)
{cv::Mat mat_front = image_to_CV_8UC1(_image);cv::Mat mat_back;cv::bitwise_not(mat_front, mat_back);if(checked) cv::imshow("image", mat_front);else cv::imshow("image", mat_back);
}

在这里插入图片描述在这里插入图片描述

distanceTransform

这个可以用来计算每个非零像素点到最近的零像素点的距离。
嗯,有点抽象,不过刚刚我们学会了手绘 Mat,
那我们可以先做个实验,看看这个距离到底是什么:

void Widget::on_pushButton_3_clicked()
{cv::Mat src(21, 21, CV_8UC1);for(int r = 0; r <= 20; r++){for(int c = 0; c <= 20; c++){if((5 < r && r < 15) && (5 < c && c < 15)) {src.at<uchar>(r, c) = 0;   // 0   - 黑} else {src.at<uchar>(r, c) = 255; // 255 - 白}}}cv::Mat dst;cv::distanceTransform(src, dst, cv::DIST_L2, 3);QString ret;for(int r = 0; r <= 20; r++){for(int c = 0; c <= 20; c++){float f = dst.at<float>(r, c);ret += QString::number(f).rightJustified(9, ' ');}   ret += "\n";}cv::imshow("dst", dst);std::cout << ret.toStdString();
}

哦,关于参数,
第一个是传入的 Mat,类型好像只能是 CV_8UC1,值只能是0或255。
第二个是得到的 Mat,只能用 at<float> 去取到它的值,这个值就是非0到最近0的距离。
第三个是距离的类型,这里用的 cv::DIST_L2,即欧几里得距离。
第四个是掩码,嗯,意义不明,取三就行。

打印结果如下:
在这里插入图片描述

  8.21576  7.80147  7.38718  6.97289  6.55859   6.1443  5.73001  5.73001  5.73001  5.73001  5.73001  5.73001  5.73001  5.73001  5.73001   6.1443  6.55859  6.97289  7.38718  7.80147  8.215767.80147  6.84647  6.43217  6.01788  5.60359   5.1893  4.77501  4.77501  4.77501  4.77501  4.77501  4.77501  4.77501  4.77501  4.77501   5.1893  5.60359  6.01788  6.43217  6.84647  7.801477.38718  6.43217  5.47717  5.06288  4.64859   4.2343  3.82001  3.82001  3.82001  3.82001  3.82001  3.82001  3.82001  3.82001  3.82001   4.2343  4.64859  5.06288  5.47717  6.43217  7.387186.97289  6.01788  5.06288  4.10788  3.69359   3.2793  2.86501  2.86501  2.86501  2.86501  2.86501  2.86501  2.86501  2.86501  2.86501   3.2793  3.69359  4.10788  5.06288  6.01788  6.972896.55859  5.60359  4.64859  3.69359  2.73859   2.3243     1.91     1.91     1.91     1.91     1.91     1.91     1.91     1.91     1.91   2.3243  2.73859  3.69359  4.64859  5.60359  6.558596.1443   5.1893   4.2343   3.2793   2.3243  1.36929 0.955002 0.955002 0.955002 0.955002 0.955002 0.955002 0.955002 0.955002 0.955002  1.36929   2.3243   3.2793   4.2343   5.1893   6.14435.73001  4.77501  3.82001  2.86501     1.91 0.955002        0        0        0        0        0        0        0        0        0 0.955002     1.91  2.86501  3.82001  4.77501  5.730015.73001  4.77501  3.82001  2.86501     1.91 0.955002        0        0        0        0        0        0        0        0        0 0.955002     1.91  2.86501  3.82001  4.77501  5.730015.73001  4.77501  3.82001  2.86501     1.91 0.955002        0        0        0        0        0        0        0        0        0 0.955002     1.91  2.86501  3.82001  4.77501  5.730015.73001  4.77501  3.82001  2.86501     1.91 0.955002        0        0        0        0        0        0        0        0        0 0.955002     1.91  2.86501  3.82001  4.77501  5.730015.73001  4.77501  3.82001  2.86501     1.91 0.955002        0        0        0        0        0        0        0        0        0 0.955002     1.91  2.86501  3.82001  4.77501  5.730015.73001  4.77501  3.82001  2.86501     1.91 0.955002        0        0        0        0        0        0        0        0        0 0.955002     1.91  2.86501  3.82001  4.77501  5.730015.73001  4.77501  3.82001  2.86501     1.91 0.955002        0        0        0        0        0        0        0        0        0 0.955002     1.91  2.86501  3.82001  4.77501  5.730015.73001  4.77501  3.82001  2.86501     1.91 0.955002        0        0        0        0        0        0        0        0        0 0.955002     1.91  2.86501  3.82001  4.77501  5.730015.73001  4.77501  3.82001  2.86501     1.91 0.955002        0        0        0        0        0        0        0        0        0 0.955002     1.91  2.86501  3.82001  4.77501  5.730016.1443   5.1893   4.2343   3.2793   2.3243  1.36929 0.955002 0.955002 0.955002 0.955002 0.955002 0.955002 0.955002 0.955002 0.955002  1.36929   2.3243   3.2793   4.2343   5.1893   6.14436.55859  5.60359  4.64859  3.69359  2.73859   2.3243     1.91     1.91     1.91     1.91     1.91     1.91     1.91     1.91     1.91   2.3243  2.73859  3.69359  4.64859  5.60359  6.558596.97289  6.01788  5.06288  4.10788  3.69359   3.2793  2.86501  2.86501  2.86501  2.86501  2.86501  2.86501  2.86501  2.86501  2.86501   3.2793  3.69359  4.10788  5.06288  6.01788  6.972897.38718  6.43217  5.47717  5.06288  4.64859   4.2343  3.82001  3.82001  3.82001  3.82001  3.82001  3.82001  3.82001  3.82001  3.82001   4.2343  4.64859  5.06288  5.47717  6.43217  7.387187.80147  6.84647  6.43217  6.01788  5.60359   5.1893  4.77501  4.77501  4.77501  4.77501  4.77501  4.77501  4.77501  4.77501  4.77501   5.1893  5.60359  6.01788  6.43217  6.84647  7.801478.21576  7.80147  7.38718  6.97289  6.55859   6.1443  5.73001  5.73001  5.73001  5.73001  5.73001  5.73001  5.73001  5.73001  5.73001   6.1443  6.55859  6.97289  7.38718  7.80147  8.21576

额,似乎有偏差?感觉明明该是整数的点却是小数。
不过偏差不大,能用就行。

试试把掩码改为5,听说这个精确一些:
在这里插入图片描述

      8.4   7.7969   7.1938   6.5907   6.3938   6.1969        6        6        6        6        6        6        6        6        6   6.1969   6.3938   6.5907   7.1938   7.7969      8.47.7969        7   6.3969   5.7938   5.3938   5.1969        5        5        5        5        5        5        5        5        5   5.1969   5.3938   5.7938   6.3969        7   7.79697.1938   6.3969      5.6   4.9969   4.3938   4.1969        4        4        4        4        4        4        4        4        4   4.1969   4.3938   4.9969      5.6   6.3969   7.19386.5907   5.7938   4.9969      4.2   3.5969   3.1969        3        3        3        3        3        3        3        3        3   3.1969   3.5969      4.2   4.9969   5.7938   6.59076.3938   5.3938   4.3938   3.5969      2.8   2.1969        2        2        2        2        2        2        2        2        2   2.1969      2.8   3.5969   4.3938   5.3938   6.39386.1969   5.1969   4.1969   3.1969   2.1969      1.4        1        1        1        1        1        1        1        1        1      1.4   2.1969   3.1969   4.1969   5.1969   6.19696        5        4        3        2        1        0        0        0        0        0        0        0        0        0        1        2        3        4        5        66        5        4        3        2        1        0        0        0        0        0        0        0        0        0        1        2        3        4        5        66        5        4        3        2        1        0        0        0        0        0        0        0        0        0        1        2        3        4        5        66        5        4        3        2        1        0        0        0        0        0        0        0        0        0        1        2        3        4        5        66        5        4        3        2        1        0        0        0        0        0        0        0        0        0        1        2        3        4        5        66        5        4        3        2        1        0        0        0        0        0        0        0        0        0        1        2        3        4        5        66        5        4        3        2        1        0        0        0        0        0        0        0        0        0        1        2        3        4        5        66        5        4        3        2        1        0        0        0        0        0        0        0        0        0        1        2        3        4        5        66        5        4        3        2        1        0        0        0        0        0        0        0        0        0        1        2        3        4        5        66.1969   5.1969   4.1969   3.1969   2.1969      1.4        1        1        1        1        1        1        1        1        1      1.4   2.1969   3.1969   4.1969   5.1969   6.19696.3938   5.3938   4.3938   3.5969      2.8   2.1969        2        2        2        2        2        2        2        2        2   2.1969      2.8   3.5969   4.3938   5.3938   6.39386.5907   5.7938   4.9969      4.2   3.5969   3.1969        3        3        3        3        3        3        3        3        3   3.1969   3.5969      4.2   4.9969   5.7938   6.59077.1938   6.3969      5.6   4.9969   4.3938   4.1969        4        4        4        4        4        4        4        4        4   4.1969   4.3938   4.9969      5.6   6.3969   7.19387.7969        7   6.3969   5.7938   5.3938   5.1969        5        5        5        5        5        5        5        5        5   5.1969   5.3938   5.7938   6.3969        7   7.79698.4   7.7969   7.1938   6.5907   6.3938   6.1969        6        6        6        6        6        6        6        6        6   6.1969   6.3938   6.5907   7.1938   7.7969      8.4

不过精确当然也有代价,比如运算速度肯定不如 3。
我们把数据改大,测测效率:

#include <QElapsedTimer>
void mask_3_VS_5(const cv::Mat& src, int mask)
{QElapsedTimer timer;timer.start();for (int i = 0; i < 10; i++) {cv::Mat dst;cv::distanceTransform(src, dst, cv::DIST_L2, mask);}qint64 elapsed = timer.nsecsElapsed();qDebug() << "mask = " << mask << ", Elapsed time:" << elapsed / 1000000.0 << "ms";
}void Widget::on_pushButton_4_clicked()
{cv::Mat src(10000, 10000, CV_8UC1);for(int r = 0; r < 10000; r++) for(int c = 0; c < 10000; c++)if((rand() % 100) < 50) src.at<uchar>(r, c) = 0;else src.at<uchar>(r, c) = 255;mask_3_VS_5(src, 5);mask_3_VS_5(src, 3);
}

10000 x 10000 的图,跑 10 次, 打印结果如下:
嗯,截图为证:
在这里插入图片描述
精度高的运行速度还更快!竟然还有这种好事😋。

获得SDF

我们已经得到了非0点到最近0点距离。
但SDF要求有正有负,即把图分为2份,一个外,一个内:
在这里插入图片描述
我们拿到一个QImage,把它转为 Mat。
其中,alpha,即透明度为 0,即纯黑的我们称为 内,其他的称为 外。
额,算了,换个说法,黑色就是障碍物,其他就是背景。
障碍物内的值为 负,外的值为 正。
那么我们拿着两个一减就得到了SDF:

// image 中, alpha为 0 的表示背景
bool image_to_SDF(const QImage& image, cv::Mat* SDF)
{int r = image.height(), c = image.width();cv::Mat mat_background(r, c, CV_8UC1);for(int i = 0; i < r; i++){for(int j = 0; j < c; j++){mat_background.at<uchar>(i, j) = (image.pixelColor(j, i).alpha() == 0) ? 0 : 255;}}if(mat_background.empty()){qDebug() << "传了个空的image计算SDF";return false;} else {qDebug() << "准备计算sdf, 地图大小: rows = " << r << ", cols = " << c;}cv::Mat mat_background_dst; // 这里面为 0 的是障碍物, 为正的是背景cv::distanceTransform(mat_background, mat_background_dst, cv::DIST_L2, 5);cv::Mat mat_front(r, c, CV_8UC1); // 这里面为 0 的是障碍物cv::Mat mat_front_dst; // 这里面为 0 的是背景, 为正的是障碍物cv::bitwise_not(mat_background, mat_front);cv::distanceTransform(mat_front, mat_front_dst, cv::DIST_L2, 5);*SDF = mat_background_dst - mat_front_dst;return true;
}

再简单测试一下:

void Widget::on_pushButton_5_clicked()
{QImage image(21, 21, QImage::Format_ARGB32);for(int i = 0; i <= 20; i++){for(int j = 0; j <= 20; j++){if((5 < i && i < 15) && (5 < j && j < 15)) {image.setPixelColor(i, j, QColor(0, 0, 0, 0)); // 透明} else {image.setPixelColor(i, j, QColor(0, 0, 0, 255));}}}cv::Mat sdf;image_to_SDF(image, &sdf);QString ret;for(int r = 0; r < sdf.rows; r++){for(int c = 0; c < sdf.cols; c++){float f = sdf.at<float>(r, c);ret += QString::number(f).rightJustified(9, ' ');}   ret += "\n";}cv::imshow("sdf", sdf);std::cout << ret.toStdString();
}

输出结果:
在这里插入图片描述
不错,和预期的一致。

然后我们再测测性能,用 10000 x 10000 的 image 跑它10次:

void Widget::on_pushButton_6_clicked()
{QImage image(10000, 10000, QImage::Format_ARGB32);for(int i = 0; i < 10000; i++){for(int j = 0; j < 10000; j++){int cur = rand() % 500 + 1;image.setPixelColor(i, j, QColor(0, 0, 0, cur < 255 ? cur : 0));}}QElapsedTimer timer;timer.start();qDebug() << "begin:" << timer.nsecsElapsed() / 1000000.0 << "ms";for (int i = 0; i < 10; i++) {cv::Mat sdf;image_to_SDF(image, &sdf);qDebug() << "第" << i << "次计算完成, time : " << timer.nsecsElapsed() / 1000000.0 << "ms";}qDebug() << "end:" << timer.nsecsElapsed() / 1000000.0 << "ms";
}

在这里插入图片描述
有点慢,但看了下,主要慢在我们每次都构造了个 cv::Mat sdf,
这里得判断 10000 x 10000次 image 是不是透明的。
那么优化方案就很明显了,我们别每次重新构造 cv::Mat 了,
我们在创建、修改 QImage时,顺便带一个 cv::Mat,
算 SDF 时,直接使用这个 cv::Mat 就行。

bool get_SDF(const cv::Mat& background, cv::Mat* SDF)
{if(background.empty()){qDebug() << "传了个空的background计算SDF";return false;} else {qDebug() << "准备计算sdf, 地图大小: rows = " << background.rows << ", cols = " << background.cols;}cv::Mat background_dst; // 这里面为 0 的是障碍物, 为正的是背景cv::distanceTransform(background, background_dst, cv::DIST_L2, 5);cv::Mat front(background.rows, background.cols, CV_8UC1); // 这里面为 0 的是障碍物cv::Mat front_dst; // 这里面为 0 的是背景, 为正的是障碍物cv::bitwise_not(background, front);cv::distanceTransform(front, front_dst, cv::DIST_L2, 5);*SDF = background_dst - front_dst;return true;
}void Widget::on_pushButton_7_clicked()
{QImage background_image(10000, 10000, QImage::Format_ARGB32);cv::Mat background_mat(10000, 10000, CV_8UC1);for(int r = 0; r < 10000; r++){for(int c = 0; c < 10000; c++){int alpha = (rand() % 2 == 0) ? 0 : (rand() % 255 + 1); // 差不多 50% 是 0background_image.setPixelColor(c, r, QColor(0, 0, 0, alpha));background_mat.at<uchar>(r, c) = (alpha == 0) ? 0 : 255;}}QElapsedTimer timer;timer.start();qDebug() << "begin:" << timer.nsecsElapsed() / 1000000.0 << "ms";for (int i = 0; i < 10; i++) {cv::Mat sdf;get_SDF(background_mat, &sdf);qDebug() << "第" << i << "次计算完成, time : " << timer.nsecsElapsed() / 1000000.0 << "ms";}qDebug() << "end:" << timer.nsecsElapsed() / 1000000.0 << "ms";
}

在这里插入图片描述
嘿嘿,非常不错,效率高多了。
至于加载,那不是我们关心的,毕竟每个游戏登录时都会让你等半天。

嗯,不过我们可以看看创建一个 10000 x 10000 的 image要多久,以及带上一个 cv::Mat又要多久:

void Widget::on_pushButton_8_clicked()
{QElapsedTimer timer;timer.start();qDebug() << "begin:" << timer.nsecsElapsed() / 1000000.0 << "ms";for(int i = 0; i < 1; i++){QImage background_image(10000, 10000, QImage::Format_ARGB32);for(int r = 0; r < 10000; r++){for(int c = 0; c < 10000; c++){int alpha = (rand() % 2 == 0) ? 0 : (rand() % 255 + 1); // 差不多 50% 是 0background_image.setPixelColor(c, r, QColor(0, 0, 0, alpha));}}}qDebug() << "end:" << timer.nsecsElapsed() / 1000000.0 << "ms";timer.restart();qDebug() << "begin:" << timer.nsecsElapsed() / 1000000.0 << "ms";for(int i = 0; i < 1; i++){QImage background_image(10000, 10000, QImage::Format_ARGB32);cv::Mat background_mat(10000, 10000, CV_8UC1);for(int r = 0; r < 10000; r++){for(int c = 0; c < 10000; c++){int alpha = (rand() % 2 == 0) ? 0 : (rand() % 255 + 1); // 差不多 50% 是 0background_image.setPixelColor(c, r, QColor(0, 0, 0, alpha));background_mat.at<uchar>(r, c) = (alpha == 0) ? 0 : 255;}}}qDebug() << "end:" << timer.nsecsElapsed() / 1000000.0 << "ms";
}

在这里插入图片描述
可以看到差不了多久,说明 cv::Mat 的创建还是很快的。

在这里插入图片描述


希望本篇文章对你有所帮助!并激发你进一步探索编程的兴趣!
本人仅是个C语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!

http://www.dtcms.com/a/440242.html

相关文章:

  • 在线制作网站宣传视频广东建设部官方网站
  • 本地做织梦网站网络推广岗位职责和任职要求
  • 什么网站可以帮人做ppt赚钱小程序开发公司哪家好?哪家最好?
  • 东莞网站建站推广网站打开wordpress
  • 交易网站开发关键字有哪些
  • 如何制作一网站wordpress删除多余图片的插件
  • 东莞网站优化建设团队如何做外贸网站推广
  • 新乡住房与城乡建设厅网站电商网站开发工作计划
  • 中国十大小说网站排名网络营销有哪些主要功能
  • 网站产品页面域名注册商城
  • 十元精品店做网站龙岩网上办事大厅官网
  • 青冈县网站建设wordpress 做下载网
  • 打开网站弹出qq做系统和做网站的区别
  • 如何建设网站的论文推广策划书模板范文
  • 网站空间500m是什么意思全国住房和城乡建设厅网站
  • 网站建站案dw如何做商业网站
  • 凡科做商品网站的教学视频淮南网站网站建设
  • 51单片机可以做网站推广app的营销方案
  • 简单模板网站制作时间做标书的网站
  • AI 智能体基本概念与架构
  • 第7章树和二叉树:树的基本概念
  • 北京建设集团网站首页镇江网站设计多少钱
  • 站长素材网兰州网站建设 冰雨
  • 哪个商城网站建设好国外企业邮箱推荐
  • 网站设计市场价有哪些在线做图的网站
  • 如何做静态页网站wordpress速度快了很多
  • 网站建设与维护 目录营销型企业网站制作公司
  • 【Linux系统】—— 程序地址空间
  • 营销型网站建设方面的书品牌广告策划方案
  • 做网站建设的怎么拓展业务wordpress 文章去掉时间