算法灰度膨胀腐蚀算子优化方法

第1章 当前灰度膨胀腐蚀算子

图像最大值最小值滤波。效果如下:

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

1.1. 常规实现

1.1.1. 半径范围遍历

对于一个像素,其膨胀腐蚀结果,查看周围半径范围内的所有像素,取最大最小值。

uint8_t nMax = 0;
for (int j = -nRY; j <= nRY; j++)
{for (int i = -nRX; i <= nRX; i++){int _X = x + i;int _Y = y + j;nMax = max(nMax, pSrc[_Y * nW + _X]);}
}
pDst[y*nW+x] = nMax;

1.1.2. 亚像素

当半径不为整数时,膨胀边缘数据会和周围像素进行插值。这是当前实现半像素套印的方式。
在这里插入图片描述

1.1.3. 当前算子存在问题

单像素处理的时间复杂度为O(N^2),当滤波半径较大时,耗时急剧上升。另外,在滤波半径接近整数时,仍然要计算亚像素,增加了耗时。
第2章 灰度膨胀腐蚀算子的优化

2.1. SIMD优化

2.1.1. 原始实现

逐像素,每个像素在半径范围内取最大最小值。

void morph(uint8_t* pSrc, uint8_t* pDst, int nW, int nH, int nRX, int nRY)
{for (int y = nRY; y < nH - nRY; y++){for (int x = nRX; x < nW - nRX; x++){uint8_t nMax = 0;for (int j = -nRY; j <= nRY; j++){for (int i = -nRX; i <= nRX; i++){int _X = x + i;int _Y = y + j;nMax = max(nMax, pSrc[_Y * nW + _X]);}}pDst[y * nW + x] = nMax;}}
}

AMD2700xCPU,2k*1k的灰度图,半径为1,耗时为33mm。

2.1.2. 每次处理32个像素

每个像素在半径范围内取最大最小值。当前VisionLink的实现

void morph2(uint8_t* pSrc, uint8_t* pDst, int nW, int nH, int nRX, int nRY)
{int x, y;for (y = nRY; y < nH - nRY; y++){//一次处理32个像素int w = nW - 2 * nRX;int n = w / 32;int t = w % 32;for (x = 0; x < n; x++){__m256i m0 = _mm256_set1_epi8(0);for (int j = -nRY; j <= nRY; j++){for (int i = -nRX; i <= nRX; i++){__m256i m1 = _mm256_loadu_si256((const __m256i*)(pSrc + (y + j)*nW + x * 32 + i));m0 = _mm256_max_epu8(m1, m0);}}_mm256_storeu_si256((__m256i*)(pDst + y*nW + x * 32), m0);}for (int k = 0; k < t; k++){uint8_t nMax = 0;for (int j = -nRY; j <= nRY; j++){for (int i = -nRX; i <= nRX; i++){int _X = x * 32 + i + k;int _Y = y + j;nMax = max(nMax, pSrc[_Y*nW + _X]);}}pDst[y*nW + x * 32 + k] = nMax;}}
}

耗时统计:2k*1k的灰度图像:

半径耗时
10.5ms
21.3ms
32.4ms
55ms
710ms

相比未优化的实现,有60倍的提升。但随着半径的增加,耗时急剧上升。

2.2. O(1)算法原理

针对随机半径,耗时上升的现象,我们期望找到0(1)的灰度膨胀腐蚀算法原理,即耗时不随着半径的增加而增加。
比如下图的原理:

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

代码实现如下:

void morph3(uint8_t* pSrc, uint8_t* pDst, int nW, int nH, int nRX, int nRY,int bDilation)
{//const int bDilation = 1;int x, y;int i, j, k;int nSizeX = nRX * 2 + 1;int nSizeY = nRY * 2 + 1;uint8_t* G = new uint8_t[nW * nSizeY];uint8_t* H = new uint8_t[nW * nSizeY];__m128i m0 = _mm_setzero_si128(), mraw, m1;auto pSrc1 = pSrc;int n1 = nW / nSizeX;int t1 = nW% nSizeX;int n2 = (nW - nRX * 2) / 16;int t2 = (nW - nRX * 2) % 16;__m128i mmask, mmasktail;if (bDilation){mmask = _mm_set_epi8(nSizeX >= 16 ? 0xff : 0x00, nSizeX >= 15 ? 0xff : 0x00,nSizeX >= 14 ? 0xff : 0x00, nSizeX >= 13 ? 0xff : 0x00,nSizeX >= 12 ? 0xff : 0x00, nSizeX >= 11 ? 0xff : 0x00,nSizeX >= 10 ? 0xff : 0x00, nSizeX >= 9 ? 0xff : 0x00,nSizeX >= 8 ? 0xff : 0x00, nSizeX >= 7 ? 0xff : 0x00,nSizeX >= 6 ? 0xff : 0x00, nSizeX >= 5 ? 0xff : 0x00,nSizeX >= 4 ? 0xff : 0x00, nSizeX >= 3 ? 0xff : 0x00,nSizeX >= 2 ? 0xff : 0x00, nSizeX >= 1 ? 0xff : 0x00);mmasktail = _mm_set_epi8(t1 >= 16 ? 0xff : 0x00, t1 >= 15 ? 0xff : 0x00,t1 >= 14 ? 0xff : 0x00, t1 >= 13 ? 0xff : 0x00,t1 >= 12 ? 0xff : 0x00, t1 >= 11 ? 0xff : 0x00,t1 >= 10 ? 0xff : 0x00, t1 >= 9 ? 0xff : 0x00,t1 >= 8 ? 0xff : 0x00, t1 >= 7 ? 0xff : 0x00,t1 >= 6 ? 0xff : 0x00, t1 >= 5 ? 0xff : 0x00,t1 >= 4 ? 0xff : 0x00, t1 >= 3 ? 0xff : 0x00,t1 >= 2 ? 0xff : 0x00, t1 >= 1 ? 0xff : 0x00);}else{mmask = _mm_set_epi8(nSizeX < 16 ? 0xff : 0x00, nSizeX < 15 ? 0xff : 0x00,nSizeX < 14 ? 0xff : 0x00, nSizeX < 13 ? 0xff : 0x00,nSizeX < 12 ? 0xff : 0x00, nSizeX < 11 ? 0xff : 0x00,nSizeX < 10 ? 0xff : 0x00, nSizeX < 9 ? 0xff : 0x00,nSizeX < 8 ? 0xff : 0x00, nSizeX < 7 ? 0xff : 0x00,nSizeX < 6 ? 0xff : 0x00, nSizeX < 5 ? 0xff : 0x00,nSizeX < 4 ? 0xff : 0x00, nSizeX < 3 ? 0xff : 0x00,nSizeX < 2 ? 0xff : 0x00, nSizeX < 1 ? 0xff : 0x00);mmasktail = _mm_set_epi8(t1 < 16 ? 0xff : 0x00, t1 < 15 ? 0xff : 0x00,t1 < 14 ? 0xff : 0x00, t1 < 13 ? 0xff : 0x00,t1 < 12 ? 0xff : 0x00, t1 < 11 ? 0xff : 0x00,t1 < 10 ? 0xff : 0x00, t1 < 9 ? 0xff : 0x00,t1 < 8 ? 0xff : 0x00, t1 < 7 ? 0xff : 0x00,t1 < 6 ? 0xff : 0x00, t1 < 5 ? 0xff : 0x00,t1 < 4 ? 0xff : 0x00, t1 < 3 ? 0xff : 0x00,t1 < 2 ? 0xff : 0x00, t1 < 1 ? 0xff : 0x00);}//处理得到前nSizeY行的结果for (k = 0; k < nSizeY; k++)  //前nSizeY行{auto pSrc1 = pSrc + k * nW;for (i = 0; i < n1; i++)  //每行有多少个分段 n1 = nW / nSizeX{mraw = _mm_loadu_si128((const __m128i*)(pSrc1 + i * nSizeX));m1 = mraw = bDilation ? _mm_and_si128(mraw, mmask) : _mm_or_si128(mraw, mmask);for (j = 1; j < nSizeX; j++)  //移位比较{mraw = _mm_slli_si128(mraw, 1);if (!bDilation) mraw = _mm_or_si128(mraw, m255);m1 = bDilation?_mm_max_epu8(m1, mraw): _mm_min_epu8(m1, mraw);}memcpy(G + k * nW + i * nSizeX, m1.m128i_u8, nSizeX);mraw = _mm_loadu_si128((const __m128i*)(pSrc1 + i * nSizeX));m1 = mraw = bDilation ? _mm_and_si128(mraw, mmask) : _mm_or_si128(mraw, mmask);for (j = 1; j < nSizeX; j++)  //移位比较{mraw = _mm_srli_si128(mraw, 1);m1 = bDilation ? _mm_max_epu8(m1, mraw) : _mm_min_epu8(m1, mraw);}memcpy(H + k * nW + i * nSizeX, m1.m128i_u8, nSizeX);}if (t1 > 0)  //边部处理{mraw = _mm_loadu_si128((const __m128i*)(pSrc1 + i * nSizeX));m1 = mraw = bDilation ? _mm_and_si128(mraw, mmask) : _mm_or_si128(mraw, mmask);for (j = 1; j < t1; j++)  //移位比较{mraw = _mm_slli_si128(mraw, 1);if (!bDilation) mraw = _mm_or_si128(mraw, m255);m1 = bDilation ? _mm_max_epu8(m1, mraw) : _mm_min_epu8(m1, mraw);}memcpy(G + k * nW + i * nSizeX, m1.m128i_u8, t1);mraw = _mm_loadu_si128((const __m128i*)(pSrc1 + i * nSizeX));m1 = mraw = bDilation ? _mm_and_si128(mraw, mmasktail) : _mm_or_si128(mraw, mmasktail);for (j = 1; j < t1; j++)  //移位比较{mraw = _mm_srli_si128(mraw, 1);m1 = bDilation ? _mm_max_epu8(m1, mraw) : _mm_min_epu8(m1, mraw);}memcpy(H + k * nW + i * nSizeX, m1.m128i_u8, t1);}}int pIndex = 0;for (y = nRY; y < nH - nRY; y++){//计算得到最大值滤波结果//从G,H中得到滤波结果for (i = 0; i < n2; i++)  //n2 = (nW / nSizeX * nSizeX - nSizeX) / 16; //每行处理多少次{__m128i mret = bDilation ? _mm_setzero_si128():_mm_set1_epi8(-1);for (j = 0; j < nSizeY; j++)  //多行比较大小{__m128i m1 = _mm_loadu_si128((const __m128i*)(G + j * nW + i * 16 + 2 * nRX));__m128i m2 = _mm_loadu_si128((const __m128i*)(H + j * nW + i * 16));m1 = bDilation ? _mm_max_epu8(m1, m2): _mm_min_epu8(m1, m2);mret = bDilation ? _mm_max_epu8(mret, m1): _mm_min_epu8(mret, m1);}_mm_storeu_si128((__m128i*)(pDst + y * nW + i * 16 + nRX), mret);}for (k = 0; k < t2; k++) //边部处理{uint8_t ret = bDilation ? 0 : 255;for (j = 0; j < nSizeY; j++){uint8_t a = (uint8_t)*(G + j * nW + i * 16 + 2 * nRX + j);uint8_t b = (uint8_t) * (H + j * nW + i * 16 + j);a = bDilation ? max(a, b):min(a,b);ret = bDilation ? max(ret, a):min(ret,a);}*(pDst + y * nW + i * 16 + nRX + k) = ret;}//更新下一行结果if (y == nH - nRY - 1)break;auto pSrc1 = pSrc + (y + nRY + 1) * nW;for (i = 0; i < n1; i++)  //每行有多少个分段 n1 = nW / nSizeX{mraw = _mm_loadu_si128((const __m128i*)(pSrc1 + i * nSizeX));m1 = mraw = bDilation ? _mm_and_si128(mraw, mmask) : _mm_or_si128(mraw, mmask);for (int j = 1; j < nSizeX; j++)  //移位比较{mraw = _mm_slli_si128(mraw, 1);if (!bDilation) mraw = _mm_or_si128(mraw, m255);m1 = bDilation ? _mm_max_epu8(m1, mraw) : _mm_min_epu8(m1, mraw);}//_mm_storeu_si128((__m128i*)(GH + pIndex*2 * nW + i * nSizeX), m1);memcpy(G + pIndex * nW + i * nSizeX, m1.m128i_u8, nSizeX);mraw = _mm_loadu_si128((const __m128i*)(pSrc1 + i * nSizeX));m1 = mraw = bDilation ? _mm_and_si128(mraw, mmask) : _mm_or_si128(mraw, mmask);for (int j = 1; j < nSizeX; j++)  //移位比较{mraw = _mm_srli_si128(mraw, 1);m1 = bDilation ? _mm_max_epu8(m1, mraw) : _mm_min_epu8(m1, mraw);}//_mm_storeu_si128((__m128i*)(GH + (pIndex*2+1) * nW + i * nSize), m1);memcpy(H + pIndex * nW + i * nSizeX, m1.m128i_u8, nSizeX);}if (t1 > 0)  //边部处理{mraw = _mm_loadu_si128((const __m128i*)(pSrc1 + i * nSizeX));m1 = mraw = bDilation ? _mm_and_si128(mraw, mmask) : _mm_or_si128(mraw, mmask);for (j = 1; j < t1; j++)  //移位比较{mraw = _mm_slli_si128(mraw, 1);if (!bDilation) mraw = _mm_or_si128(mraw, m255);m1 = bDilation ? _mm_max_epu8(m1, mraw) : _mm_min_epu8(m1, mraw);}memcpy(G + pIndex * nW + i * nSizeX, m1.m128i_u8, t1);mraw = _mm_loadu_si128((const __m128i*)(pSrc1 + i * nSizeX));m1 = mraw = bDilation ? _mm_and_si128(mraw, mmasktail) : _mm_or_si128(mraw, mmasktail);for (j = 1; j < t1; j++)  //移位比较{mraw = _mm_srli_si128(mraw, 1);m1 = bDilation ? _mm_max_epu8(m1, mraw) : _mm_min_epu8(m1, mraw);}memcpy(H + pIndex * nW + i * nSizeX, m1.m128i_u8, t1);}pIndex = (pIndex + 1) % nSizeY;}//delete[] GH;delete[] G;delete[] H;
}

在如下链接https://www.cnblogs.com/Imageshop/p/7018510.html,有一个另外的实现,本实现占用空间少,且耗时更短。唯一的问题的支持的最大半径为7,可以通过升级为AVX2,最大支持15。
耗时统计如下:

半径耗时
12.2ms
22.2ms
32.3ms
52.6ms
72.7ms

基本上做到了O(1),但是,基础的耗时太长。

2.3. halcon,opencv

那么,halcon,opencv可以做到多块呢?
以下是Halcon测试代码:

 	HObject  ho_Image1, ho_Red, ho_Green, ho_Blue;HObject  ho_GrayImage, ho_ImageMin;SetSystem("parallelize_operators", "false");ReadImage(&ho_Image1, "D:/1.bmp");//Decompose3(ho_Image1, &ho_Red, &ho_Green, &ho_Blue);Rgb1ToGray(ho_Image1, &ho_GrayImage);auto start = high_resolution_clock::now();for (int i = 0; i < 1000; i++)GrayDilationShape(ho_GrayImage, &ho_ImageMin, 9, 9, "rectangle");auto stop = high_resolution_clock::now();auto duration = duration_cast<microseconds>(stop - start);cout << "t:" << duration.count() / 1000.0 << "ms" << endl;WriteImage(ho_ImageMin, "bmp", 0, "D:/2H.bmp");

通过SetSystem(“parallelize_operators”, “false”);来控制是否开启并行,以防halcon不讲武德。
以及OpenCV的测试代码:

	cv::Mat src, dst;src = cv::imread("D:\\1.bmp", cv::IMREAD_GRAYSCALE); // Read the fileif (src.empty()){cout << "Could not open or find the image" << endl;return -1;}cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(15, 15));auto start = high_resolution_clock::now();for(int i = 0;i<10000;i++)cv::morphologyEx(src, dst, cv::MORPH_ERODE, element);auto stop = high_resolution_clock::now();auto duration = duration_cast<microseconds>(stop - start);cout << "Time taken by function: "<< duration.count()/1000.0<< "ms" << endl;imwrite("D:\\2.bmp", dst);

耗时分别如下:

半径halconHalcon 并行OpenCV
10.30.20.3
20.60.30.4
30.90.40.6
51.30.60.8
72.30.81.1

2.4. 行列分开方式

既然halcon也没有使用O(1)的算法原理,说明O(1)是有代价的,基础耗时就比较高。至少在半径小于10的情况下,Halcon的灰度膨胀腐蚀算子耗时都是递增的。
再就是行列分开的方法了,代码实现如下:

void morph4(uint8_t* pSrc, uint8_t* pDst, int nW, int nH, int nRX, int nRY, int bDilation)
{int halfRow = nRY;int halfCol = nRX;uint8_t* pTmp = new uint8_t[nW * nH];int nCol = nW % 32 == 0 ? nW / 32 : nW / 32 + 1;int* nOffsetX = new int[nCol];memset(nOffsetX, 0, sizeof(int) * nCol);nOffsetX[nCol - 1] = nW % 32 == 0 ? 0 : 32 - nW % 32;//处理列for (int i = 0; i < nH; i++){uint8_t* pSrc1 = pSrc + i * nW;uint8_t* pTmp1 = pTmp + i * nW;for (int j = 0; j < nW; j += 32

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1557997.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

《重生到现代之从零开始的C语言生活》—— 联合体和枚举

联合体 像结构体一样&#xff0c;联合体也是由一个或多个成员构成 但是只会给最大的成员分配内存&#xff0c;联合体的特点就是所有成员共用一块内存空间&#xff0c;所以也叫共同体 由于所有的成员共用一块内存空间&#xff0c;所以如果给其中的一个成员赋值的话&#xff0…

Ubuntu修改IP方法

方法一&#xff1a;通过图形化界面修改IP 打开网络设置&#xff1a; 点击桌面右上角的网络图标&#xff0c;然后选择“设置”或“网络设置”。 选择网络接口&#xff1a; 在网络设置窗口中&#xff0c;选择你正在使用的网络接口&#xff08;有线或无线网络&#xff09;。 进…

避雷!Google Adsense联盟营销七大投放误区

你是否在使用Google AdSense进行广告投放&#xff1f;你是否想进一步优化你的投放策略&#xff1f;那么这篇文章你不可错过啦&#xff01; Google AdSense为跨境商家提供了一个平台&#xff0c;我们可以通过展示相关广告来赚取收入。然而&#xff0c;即使是最有经验的商家也可…

ReentrantLock相关知识

加锁流程 公平锁加锁流程&#xff1a; public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt(); } 加锁流程主要分三大步&#xff1a; tryAcquire尝试获取锁 protected final boolean tryAc…

C++nullptr

其实理解nullptr很简单&#xff0c;它其实就是将一个指针置为空 int* arrnullptr; 但是为什么C语言明明有NULL可以将指针置为空&#xff0c;C还要引入nullptr呢 其实简单理解C语言的NULL它其实是一个宏 #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NUL…

【Agent】Cognitive Architectures for Language Agents

arxiv: https://arxiv.org/abs/2309.02427 背景 现有的Agent框架&#xff0c;大部分是基于强化学习提出的框架。本文结合生产系统和认知科学&#xff0c;提出了一个结构化和模块化的Agent架构。 2、记忆 记忆可分为两类&#xff1a; 工作记忆&#xff08;短期记忆&#xf…

多线程股吧(东方财富)用户信息爬取

多线程东方财富&#xff08;股吧&#xff09;用户信息爬取 在上一篇博客股吧信息爬取的基础上加入了多线程&#xff0c;使得速度提升了十几倍&#xff0c;爬取内容如下&#xff1a; 最终爬取结果如下&#xff1a; 完整代码如下&#xff08;准备好环境&#xff0c;比如pytho…

近年来自动驾驶行业就业与企业需求情况

自动驾驶行业在近年来持续发展&#xff0c;就业情况和企业需求呈现出多样化和复杂化的趋势。 以下是基于我搜索到的资料对自动驾驶行业最新就业情况和企业需求的详细分析&#xff1a; 自动驾驶行业对高端技术人才的需求非常旺盛&#xff0c;尤其是架构工程师、算法工程师等岗…

Qt(10.8)

作业&#xff1a;完善登录界面 源文件 #include "widget.h" #include "ui_widget.h" #include<QDebug> #include<QLabel> #include<QMessageBox> Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setu…

【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则

文章目录 C 继承详解&#xff1a;初阶理解与实战应用前言第一章&#xff1a;继承的基本概念与定义1.1 继承的概念1.2 继承的定义 第二章&#xff1a;继承中的访问权限2.1 基类成员在派生类中的访问权限2.2 基类与派生类对象的赋值转换2.2.1 派生类对象赋值给基类对象2.2.2 基类…

leetcode68:文本左右对齐

给定一个单词数组 words 和一个长度 maxWidth &#xff0c;重新排版单词&#xff0c;使其成为每行恰好有 maxWidth 个字符&#xff0c;且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单词&#xff1b;也就是说&#xff0c;尽可能多地往每行中放置单词。必要时可…

Ubuntu 22.04 安装 KVM

首先检查是否支持 CPU 虚拟化&#xff0c;现在的 CPU 都应该支持&#xff0c;运行下面的命令&#xff0c;大于0 就是支持。 egrep -c (vmx|svm) /proc/cpuinfo安装 Libvirt apt install -y qemu-kvm virt-manager libvirt-daemon-system virtinst libvirt-clients bridge-uti…

DAMA数据管理知识体系(第11章 数据仓库和商务智能)

课本内容 11.1 引言 概要 数据仓库被公认为企业数据管理的核心语境关系图 图11-1 语境关系图&#xff1a;数据仓库和商务智能业务驱动因素 运营支持职能合规需求商务智能活动目标和原则 目标 一个组织建设数据仓库的目标通常有&#xff1a; 1&#xff09;支持商务智能活动。 2&…

易图讯军用VR三维电子沙盘系统

深圳易图讯军用VR三维电子沙盘系统是一种集成了虚拟现实&#xff08;VR&#xff09;技术、三维建模技术、大数据分析、实时动态更新以及高度安全可靠的综合性军事指挥平台。该系统通过高精度三维模型真实再现战场环境&#xff0c;为指挥员提供沉浸式体验和交互操作的可能性&…

数据结构与算法——Java实现 31.阻塞队列

—— 24.10.8 一、问题提出 目前队列存在的问题 1.很多场景要求分离生产者、消费者两个角色、它们需要由不同的线程来担当&#xff0c;而之前的实现根本没有考虑线程安全问题 2.poll方法&#xff0c;队列为空&#xff0c;那么在之前的实现里会返回null&#xff0c;如果就是硬…

构建MySQL健康检查Web应用

构建MySQL健康检查Web应用 在这里将探讨如何将MySQL健康检查功能转换为一个功能完整的Web应用。这个应用允许用户通过简单的Web界面执行MySQL健康检查&#xff0c;并查看详细的结果。我们将逐步介绍代码实现、改进过程以及如何设置和运行这个应用。 1. MySQL健康检查类 首先…

codetop标签双指针题目大全解析(二),双指针刷穿地心!!!!!

复习比学习更重要&#xff0c;如果忘了就跟没学是一样的 1.和为k的子数组2.统计[优美子数组]3.区间列表的交集4.将x减到0的最小操作5.替换子串得到平衡字符串6.划分字母区间7.分隔链表8.通过删除字母匹配到字典里最长单词9.寻找目标值-二维数组10.至多包含两个不同字符的最长子…

麒麟系统串口配置篇

麒麟系统串口配置篇 1.配置串口驱动&#xff08;编译/动态加载串口&#xff09; 解压文件夹,然后在解压后的文件夹所在目录&#xff0c;右键选择打开终端&#xff0c;依次执行以下命令&#xff1a; 以麒麟系统下的CH341串口驱动为例&#xff0c;解压CH341SER_LINUX.zip sudo…

2024_10_8 系统进展

改进位置 发现是label_api里藏了我需要改进的东西 settings.py 数据库 我这边电脑上使用的是windows 192 vue.config.js 陈家强是这样设置的 module.exports {publicPath: process.env.NODE_ENV production? /: /,assetsDir: static,// css: {// extract: false// },…

【C++ 11】for 基于范围的循环

文章目录 【 1. 基本用法 】【 2. for 新格式的应用 】2.1 for 遍历字符串2.2 for 遍历列表2.3 for 遍历的同时修改元素 问题背景 C 11标准之前&#xff08;C 98/03 标准&#xff09;&#xff0c;如果要用 for 循环语句遍历一个数组或者容器&#xff0c;只能套用如下结构&#…