图像处理与图像分析—图像统计特性的计算(纯C语言实现灰度值显示)

news/2024/7/27 12:21:39/文章来源:https://blog.csdn.net/Ochazuke/article/details/136606958

根据输入的灰度图像,分别计算图像的均值、方差等统计特征,并计算图像的直方图特征并以图形方式显示图像的直方图(用C或C++语言实现)。

学习将会依据教材图像处理与图像分析基础(C/C++)版内容展开

在上个笔记中,我们成功对bmp图像进行了读取,那么这次我们将会尝试计算图像的均值、方差等统计特征,并计算图像的直方图特征并以图形方式显示图像的直方图

首先分析一下我们需要的功能:

  • 能够读取图片
  • 分析图片每一个像素的灰度值
  • 把每一个像素的灰度值存入灰度数组
  • 用直方图的形式进行展示
  • 计算图像的均值,方差

那么上笔记的代码已经可以实现:图片的读取,分析灰度值,那么我们只需要再加上后面三个功能即可

首先我们还是先来分析书上的代码

算法【2-2】统计灰度直方图

void GetHistogram(BYTE* pGryImg, int width, int height, int* histogram)
{BYTE * pCur, * pEnd = pGryImg + width * height;//step.1 初始化//for(int g = 0;g < 256;g++) histogram[g] = 0;memset(histogram, 0, sizeof(int) * 256);//step.2 直方图统计for (pCur = pGryImg; pCur < pEnd;)histogram[*(pCur++)]++;//step.3 结束return;
}

还是先让我来浅浅的注释一下,看看能理解多少

//pGryImg: 指向灰度图像数据的指针
//width: 图像宽度
//height: 图像高度
//histogram: 存储直方图数据的数组
void GetHistogram(BYTE* pGryImg, int width, int height, int* histogram) {BYTE *pCur, *pEnd = pGryImg + width * height; // 定义指针变量并指向图像数据起始位置和结束位置// Step 1: 初始化直方图数组// 使用memset函数将直方图数组所有元素初始化为0memset(histogram, 0, sizeof(int) * 256);// Step 2: 直方图统计// 遍历灰度图像数组,对每个灰度值出现的次数进行统计for (pCur = pGryImg; pCur < pEnd;) {histogram[*(pCur++)]++; // 获取当前像素的灰度值并递增对应直方图计数}// Step 3: 函数结束return;
}

不是很难,可以试一下,首先还是写成C语言

void GetHistogram(uint8_t* pImg, int width, int height, int* histogram)
{uint8_t* pCur;uint8_t* pEnd = pImg + width * height;// 初始化直方图数组memset(histogram, 0, sizeof(int) * 256);// 直方图统计for (pCur = pImg; pCur < pEnd;){histogram[*pCur]++;pCur++}// 函数结束return;
}

我们用之前写好的代码(图片的读入中的源代码)稍稍修改一下

还是使用这张图片

ME

传入参数少了一个histogram,我们需要创建一个histogram数组

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>void GetHistogram(uint8_t* pImg, int width, int height, int* histogram)
{uint8_t* pCur;uint8_t* pEnd = pImg + width * height;// 初始化直方图数组memset(histogram, 0, sizeof(int) * 256);// 直方图统计for (pCur = pImg; pCur < pEnd;){histogram[*pCur]++;pCur++}// 函数结束return;
}int main()
{int histogram[256];//建立一个数组const char* filename = "E:/code/IDP-Learning-Journey/images/ME.bmp";FILE* file = fopen(filename, "rb");uint8_t bmpHeader[54];size_t bytesRead = fread(bmpHeader, 1, 54, file);int width = *(int*)&bmpHeader[18];   // 宽度信息位于偏移量为 18 的位置int height = *(int*)&bmpHeader[22];  // 高度信息位于偏移量为 22 的位置uint8_t* imageData = (uint8_t*)malloc(width * height); fseek(file, 54, SEEK_SET);  // 跳过 BMP 文件头bytesRead = fread(imageData, 1, width * height, file); GetHistogram(imageData, width, height,histogram);for (int i = 0; i < 256; i++){printf("histogram[%d]: %d\n", i, histogram[i]);}//打印出来看看结果是否成功fclose(file);free(imageData);return 0;
}

image-20240309230227278

成功实现预期功能,接下来查找如何显示为直方图

通过我的不懈努力,变成了这样

image-20240309230633643

很显然,还是没达到要求,这个时候只能网上查一下了

好像解决办法很少,但是还是查到了一个头文件,可以解决C语言生成图片的问题

#include <SDL.h>

SDL(Simple DirectMedia Layer)是一个跨平台的开源多媒体库,用于实现音频、视频、图形和输入设备的访问。SDL提供了一套简单而强大的接口,使得开发者能够在不同平台上编写高性能的多媒体应用程序,而不需要关注底层的细节。

我们用不到那么多功能,只需要能打开一个图形化页面就行


配置SDL

首先需要去GitHub上找到相应的包克隆到本地

Release 2.30.1 · libsdl-org/SDL (github.com)

image-20240310121243846

选择对应的版本,要区分mingw和MSVC编译器,后者也就是vs的编译器

下载到一个能找到的位置解压缩

image-20240310121528238

这里我演示一下如何配置vs2022的环境,如果是mingw,国内很多开源社区都有教程,就不过多去演示了,参考官方文档

step.1 点击项目中的属性
image-20240310121717504
step.2 修改VC++目录下的包含目录为解压目录下的include文件夹的地址

image-20240310121935263

step.3 修改库目录为解压目录下lib地址

image-20240310122117131

step.4 在链接器选择输入,修改附加依赖项为lib目录下lib后缀文件的名称

image-20240310122305329

step5 修改环境变量

首先需要添加lib目录下64位文件夹的地址

image-20240310122451516

接着是我实验发现,总是会报找不到SDL2.dll这个文件的错误,导致程序无法编译,我尝试把这个文件直接放在.c文件的目录下,可以解决问题,但是以后不想这么麻烦,所以我们把这个文件也添加系统变量

image-20240310122744885

问题解决,编译器可以编译,我们现在让chatgpt写一段小程序验证一下

image-20240310122943972

测试代码

#include <stdio.h>
#include <SDL.h>int main() {SDL_Init(SDL_INIT_VIDEO);// 创建窗口SDL_Window* window = SDL_CreateWindow("SDL Example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, 0);// 创建渲染器SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);// 设置绘制颜色为红色SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);// 清空屏幕SDL_RenderClear(renderer);// 创建一个矩形SDL_Rect rect = { 100, 100, 200, 150 };// 填充矩形SDL_RenderFillRect(renderer, &rect);// 更新屏幕SDL_RenderPresent(renderer);// 等待2秒SDL_Delay(2000);// 清理资源SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();return 0;
}

这样就配置成功了


SDL是如何绘图的

这个问题很重要,如果不搞清楚我们将无法绘制灰度值直方图

查了一下,分为以下几步

  • 初始化sdl

    这一步是为了指定要使用的SDL子系统,比如视频子系统、音频子系统、定时器子系统等。可以选择仅初始化所需的子系统,以提高性能和减少资源占用。*

SDL_Init(SDL_INIT_VIDEO);//我们使用的画图窗口用的是视频子系统
  • 创建窗口

    创建一个来展示我们直方图数据的窗口

SDL_Window* window = SDL_CreateWindow("Histogram", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 512, 512, SDL_WINDOW_SHOWN);//窗口名称为直方图,接下来两个参数是窗口在屏幕上的位置,分别在水平和垂直都居中显示,窗口的宽度和高度目前按时512和512,这个后面再调整,再后面一个参数的意思是创建窗口立即显示
  • 创建渲染器

    这一步不是很能理解,在我的理解里应该是类似于创建一个画板,可以在窗口里作图的功能

SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);//window为要在其上创建渲染器的窗口指针,-1:指定要使用的渲染器索引。通常将其设置为-1,以便SDL自动选择可用的索引。SDL_RENDERER_ACCELERATED:指定渲染器使用硬件加速,以提高性能。
  • 设置背景颜色

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);//设置绘制颜色设置为黑色(RGB值为0, 0, 0,表示红、绿、蓝通道均为0,即黑色),同时将透明度设置为255(不透明)SDL_RenderClear(renderer);//然后通过SDL_RenderClear函数清空渲染器,实际上是在规定背景颜色。
    

    在使用SDL进行图形绘制时,首先通常会设置绘制颜色,然后使用SDL_RenderClear函数填充整个渲染目标(通常是窗口)的背景色。

  • 绘制直方图

    我尝试了使用for循环每次改变x坐标,y坐标为数组中的值,但是好像失败了

image-20240310130657225

先看代码

 int barWidth = 2;// 设置每个直方条的宽度for (int i = 0; i < size; i++) {SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);//设置白色// 计算直方条的位置和高度int barX = i * (barWidth + 1);int barY = histogram[i];SDL_Rect bar = { barX, barY, barWidth, (int)(histogram[i]) };SDL_RenderFillRect(renderer, &bar);}// 绘制SDL_RenderPresent(renderer); // 更新renderer

难道是因为,直方图太小了直接看不到吗,如果限定一个高度区间会不会好一点

我思路是这样的

  1. 找到灰度值的最大值
  2. 用规定的最大值去比上灰度值的最大值得到一个比例
  3. 这样所有的灰度值都乘上这个比例,就可以等比例缩放了

ok,用for循环找最大值和最小值

    int maxBarHeight = 0;int minBarHeight = 0;for (int i = 0; i < size; i++) {if (histogram[i] > maxBarHeight) {maxBarHeight = histogram[i];}}for (int i = 0; i < size; i++) {if (histogram[i] < minBarHeight) {minBarHeight = histogram[i];}}

这样子就有最大值和最小值了,我们的最大值设定为400,因为窗口为512,

宽度还为2,刚好填满窗口

int barWidth = 2;
double k = (double)(400) / maxBarHeight;//设比值为k,定义双精度浮点数400,防止整数相除默认算整数for (int i = 0; i < size; i++) {SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);//设置绘制颜色为白色int barX = i * barWidth + 1;//每一个x坐标都为循环次数X宽度int barY = y - (int)(histogram[i] * k);//这里xy都为每一个柱子左上角点的坐标// 绘制直方条SDL_Rect bar = { barX, barY, barWidth, (int)(histogram[i] * k) };//传递参数为,直方图左上角点的坐标,直方图的宽度和高度SDL_RenderFillRect(renderer, &bar);
}

看一下效果

image-20240310133228536

对比一下Photoshop的直方图

image-20240310133811221

再调整一下,把窗口改为512X256,高度改为两百

image-20240310134311229

但是只能展示一瞬间,然后就会结束程序,查过资料之后发现可以添加以下代码来延长展示时间

    SDL_Event event;int quit = 0;while (!quit) {while (SDL_PollEvent(&event)) {if (event.type == SDL_QUIT) {quit = 1;}}}

再次测试可以正常展示,完成目标。

源代码:

#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <SDL.h>void displayHistogram(const int* histogram, int size) {SDL_Init(SDL_INIT_VIDEO);SDL_Window* window = SDL_CreateWindow("Histogram", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 512, 256, SDL_WINDOW_SHOWN);SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);if (renderer == NULL) {printf("Failed to create renderer: %s\n", SDL_GetError());return;}SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);SDL_RenderClear(renderer);int maxBarHeight = 0;int minBarHeight = 0;for (int i = 0; i < size; i++) {if (histogram[i] > maxBarHeight) {maxBarHeight = histogram[i];}}for (int i = 0; i < size; i++) {if (histogram[i] < minBarHeight) {minBarHeight = histogram[i];}}int y = 250;int barWidth = 2;double k = (double)(200) / maxBarHeight;for (int i = 0; i < size; i++) {SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);int barX = i * barWidth + 1;int barY = y - (int)(histogram[i] * k);SDL_Rect bar = { barX, barY, barWidth, (int)(histogram[i] * k) };SDL_RenderFillRect(renderer, &bar);}SDL_RenderPresent(renderer);SDL_Event event;int quit = 0;while (!quit) {while (SDL_PollEvent(&event)) {if (event.type == SDL_QUIT) {quit = 1;}}}SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();
}void GetHistogram(uint8_t* pImg, int width, int height, int* histogram)
{uint8_t* pCur;uint8_t* pEnd = pImg + width * height;// 初始化直方图数组memset(histogram, 0, sizeof(int) * 256);// 直方图统计for (pCur = pImg; pCur < pEnd;){histogram[*pCur]++;pCur++;}// 函数结束return;
}int main()
{int histogram[256];//建立一个数组const char* filename = "E:/code/IDP-Learning-Journey/images/ME.bmp";FILE* file = fopen(filename, "rb");uint8_t bmpHeader[54];size_t bytesRead = fread(bmpHeader, 1, 54, file);int width = *(int*)&bmpHeader[18];   // 宽度信息位于偏移量为 18 的位置int height = *(int*)&bmpHeader[22];  // 高度信息位于偏移量为 22 的位置uint8_t* imageData = (uint8_t*)malloc(width * height);fseek(file, 54, SEEK_SET);  // 跳过 BMP 文件头bytesRead = fread(imageData, 1, width * height, file);GetHistogram(imageData, width, height,histogram);displayHistogram(histogram, 256);fclose(file);free(imageData);return 0;
}

好的,我们目前还需要展示图像的均值和方差以及各部分信息,首先是均值

均值

没有想到特别好的办法,只能想到所有的灰度值相加,除以总的像素数

用C语言写一个函数,传入值为数组元素和宽度以及高度像素信息

double mean(const int* histogram, int width, int height)
{size_t sum = 0;size_t totalPixels = width * height;for (size_t i = 0; i < 256; i++){     sum += i * histogram[i];}double a = (double)sum / totalPixels;return a;
}

其实这里没必要用size_t,是因为我之前思路有问题,一直内存溢出,数字不够存,改变思路后可以成功计算

image-20240310173812290

标准差

也同样没想到什么好的方法,只能想到用循环,对每个像素值与均值之差的平方求和,并除以像素总数减一

写一下代码

double Variance(const int* histogram, int width, int height,double mean)
{double variance = 0.0;for (size_t i = 0; i < width * height; i++) {variance += pow(histogram[i] - mean, 2);}variance /= (width * height - 1);return variance
}

出现问题

for (size_t i = 0; i < width * height; i++)
{printf("%d\n", i);//检查发现循环次数无法达到1000000次以上variance += pow(histogram[i] - mean, 2);
}
原因是因为width * height数值太大,需要强制类型转换
不是上面的原因,因为灰度值图像中并没有这么多内存格子,我理解错了

这才是正确的,我真的是看了半个小时,取的数据不是图片所有的数据,而是直方图数据

image-20240310181201358

double StandardDeviation(const int* histogram, int width, int height, double mean)
{double variance = 0.0;int totalPixels = width * height;for (int i = 0; i < 256; i++){variance += pow(i - mean, 2) * histogram[i];}//计算每一个色度值和均值的差的平方再乘上个数得到和最后开平方就可以得到标准差variance /= (totalPixels - 1);double standardDeviation = sqrt(variance);return standardDeviation;
}

image-20240310182432079

差的不是很多,我查了一下原因,应该是因为Photoshop统计的是rgb的标准差和均值,我们计算的是灰度值的标准差和均值

中间值

字如其名,我们只要找到最中间的像素即可

double Median(const int* histogram, int width, int height)
{int size = width * height; int cumulativeSum = 0;int middleElement = (size + 1) / 2;for (int i = 0; i < 256; ++i){cumulativeSum += histogram[i];if (cumulativeSum >= middleElement){return i;}}return 0; 
}

真的是最顺利的一次

image-20240310182856703

明度和对比度

这个我们一起来看书上【程序 2-5】

void GetBrightContrast(int * histogram,double * bright,double * contrast)
{int g;double sum,num;//书上说图像很亮时,int有可能会溢出,所以我这里直接用doubledouble fsum;//step.1 求亮度for(sum = num = 0, g = 0; g < 256 ; g++){sum += histogram[g] * g;num += histogram[g];}* bright = sum * 1.0/num;//step.2 求对比度for(fsum = 0.0,g = 0;g < 256;g++){fsum += histogram[g]*(g - *bright) * (g - *bright);}* contrast = sqrt(fsum/(num - 1));//即Std Dev//step.3 结束return;
}

好的观察后发现,明度就是均值,对比度就是标准差

我前面相当于白头脑风暴了

很容易理解我就不再注释了,看一下运行结果

image-20240310184356037

前面还是有点小问题,咱们先用后面的代码,那这样,我们就已经成功得到了图片的亮度,对比度,以及中间值,那么怎么写进直方图里呢

好的,我也没找到好的办法,最好的办法是用SDL的文字库,继续网上加

但是我在测试代码的时候一直提示没有这个库,后来我就想到了能不能直接加在标题上

于是我就创建了一串字符串用作标题,上面传入了计算的明度,对比度以及中间值的数据

代码如下

    char windowTitle[100];sprintf(windowTitle, "Histogram      Brightness: %.2f  Contrast: %.2f  Median: %.2f", a, b, c);SDL_Window* window = SDL_CreateWindow(windowTitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 512, 256, SDL_WINDOW_SHOWN);

详细的讲解在上面讲过,这里就不过多赘述了

我知道这个方法可能的确有点投机取巧了,后面也会去寻找解决办法,我觉得Qt虽然能解决,但是还是更想用C语言去自己敲一遍,这个找到解决办法了再来更新笔记

结果

不过我们看一下运行结果

image-20240310191200504

还是很不错的,对比一下Photoshop

image-20240310191246210

是很接近的,可能偏差的原因就是ps用的是rgb,我只用了单通道的灰度值

总体来看不是很难,但是细节很多,需要对C语言有深刻的了解,接下来我把源码放在下面

#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <SDL.h>void displayHistogram(const int* histogram, int size,double a,double b,double c) 
{SDL_Init(SDL_INIT_VIDEO);char windowTitle[100];sprintf(windowTitle, "Histogram      Brightness: %.2f  Contrast: %.2f  Median: %.2f", a, b, c);SDL_Window* window = SDL_CreateWindow(windowTitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 512, 256, SDL_WINDOW_SHOWN);SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);if (renderer == NULL) {printf("Failed to create renderer: %s\n", SDL_GetError());return;}SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);SDL_RenderClear(renderer);int maxBarHeight = 0;int minBarHeight = 0;for (int i = 0; i < size; i++) {if (histogram[i] > maxBarHeight) {maxBarHeight = histogram[i];}}for (int i = 0; i < size; i++) {if (histogram[i] < minBarHeight) {minBarHeight = histogram[i];}}int y = 250;int barWidth = 2;double k = (double)(200) / maxBarHeight;for (int i = 0; i < size; i++) {SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);int barX = i * barWidth + 1;int barY = y - (int)(histogram[i] * k);SDL_Rect bar = { barX, barY, barWidth, (int)(histogram[i] * k) };SDL_RenderFillRect(renderer, &bar);}SDL_RenderPresent(renderer);SDL_Event event;int quit = 0;while (!quit) {while (SDL_PollEvent(&event)) {if (event.type == SDL_QUIT) {quit = 1;}}}SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();
}void GetHistogram(uint8_t* pImg, int width, int height, int* histogram)
{uint8_t* pCur;uint8_t* pEnd = pImg + width * height;// 初始化直方图数组memset(histogram, 0, sizeof(int) * 256);// 直方图统计for (pCur = pImg; pCur < pEnd;){histogram[*pCur]++;pCur++;}// 函数结束return;
}double mean(const int* histogram, int width, int height)
{size_t sum = 0;size_t totalPixels = width * height;for (size_t i = 0; i < 256; i++){sum += i * histogram[i]; // 将像素值乘以出现次数再累加}double a = (double)sum / totalPixels;return a;
}double StandardDeviation(const int* histogram, int width, int height, double mean)
{double variance = 0.0;int totalPixels = width * height;for (int i = 0; i < 256; i++){variance += pow(i - mean, 2) * histogram[i];}variance /= (totalPixels - 1);double standardDeviation = sqrt(variance);return standardDeviation;
}double Median(const int* histogram, int width, int height)
{int size = width * height;int cumulativeSum = 0;int middleElement = (size + 1) / 2;for (int i = 0; i < 256; ++i){cumulativeSum += histogram[i];if (cumulativeSum >= middleElement){return i;}}return 0;
}void GetBrightContrast(int * histogram,double * bright,double * contrast)
{int g;double sum,num;//书上说图像很亮时,int有可能会溢出,所以我这里直接用doubledouble fsum;//step.1 求亮度for(sum = num = 0, g = 0; g < 256 ; g++){sum += histogram[g] * g;num += histogram[g];}* bright = sum * 1.0/num;//step.2 求对比度for(fsum = 0.0,g = 0;g < 256;g++){fsum += histogram[g]*(g - *bright) * (g - *bright);}* contrast = sqrt(fsum/(num - 1));//即Std Dev//step.3 结束return;
}int main()
{int histogram[256];//建立一个数组const char* filename = "E:/code/IDP-Learning-Journey/images/ME.bmp";FILE* file = fopen(filename, "rb");uint8_t bmpHeader[54];size_t bytesRead = fread(bmpHeader, 1, 54, file);int width = *(int*)&bmpHeader[18];   // 宽度信息位于偏移量为 18 的位置int height = *(int*)&bmpHeader[22];  // 高度信息位于偏移量为 22 的位置uint8_t* imageData = (uint8_t*)malloc(width * height);fseek(file, 54, SEEK_SET);  // 跳过 BMP 文件头bytesRead = fread(imageData, 1, width * height, file);GetHistogram(imageData, width, height,histogram);double meanValue = 0;double StandardDeviationValue = 0;double median = 0;double bright, contrast;GetBrightContrast(histogram, &bright, &contrast);median = Median(histogram, width, height);//printf("中间值(Median):%f\n", median);//printf("亮度(Brightness): %lf\n", bright);//printf("对比度(Contrast): %lf\n", contrast);displayHistogram(histogram, 256, bright, contrast,median);fclose(file);free(imageData);return 0;
}

感谢您的阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTP/2的三大改进:头部压缩、多路复用和服务器推送

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Midjourney绘图欣赏系列【人物篇】(一)

Midjourney介绍 Midjourney 是生成式人工智能的一个很好的例子&#xff0c;它根据文本提示创建图像。它与 Dall-E 和 Stable Diffusion 一起成为最流行的 AI 艺术创作工具之一。与竞争对手不同&#xff0c;Midjourney 是自筹资金且闭源的&#xff0c;因此确切了解其幕后内容尚不…

微信小程序一次性订阅requestSubscribeMessage授权和操作详解

一次性订阅&#xff1a;用户订阅一次发一次通知 一、授权 — requestSubscribeMessage Taro.requestSubscribeMessage({tmplIds: [], // 需要订阅的消息模板的id的集合success (res) {console.log("同意授权", res)},fail(res) {console.log(拒绝授权, res)}})点击或…

Java爬虫-获取数据的方式之一

目录 一、jsoup的使用 1.概述 2.主要功能 3.快速入门 4.数据准备 二、Selenium 1.概述 2.使用 三、Selenium配合jsoup获取数据 四、爬虫准则 五、Seleniumjsoupmybatis实现数据保存 1.筛选需要的数据 2.创建一个表&#xff0c;准备存储数据 手写&#xff1f;不存在…

el-Upload 上传组件,on-success方法response返回值为空

前言 家人们谁懂啊&#xff0c;我最近在用el-upload组件做上传用户的头像的功能&#xff0c;用的是它自带的action方法自动上传&#xff0c;它不是有个on-success方法吗&#xff0c;是个回调函数&#xff0c;上传成功后会返回三个参数&#xff0c;response&#xff08;是一个表…

使用Barrier共享鼠标键盘,通过macos控制ubuntu系统

之前文章写过如何使用barrrier通过windows系统控制ubuntu系统&#xff0c;该文章将详细介绍如何使用barrier通过macos系统控制ubuntu系统 一、macOS安装barrier macOS版本barrier链接 1、双击点开安装包 2、将安装包里的barrier拷贝到macOS的达达->应用程序中 3、在达达…

[QT]自定义的QtabWidget

需求 最近有一个需求就是一个QTabWidget要求有四个tab页在左侧用于显示主页面&#xff0c;在右侧有一个关于按钮&#xff0c;点击后用于弹出窗口显示一些程序相关信息。主要是怎么实现右侧按钮 相关代码 #ifndef MYTABWIDGET_H #define MYTABWIDGET_H#include <QWidget&g…

元宇宙崛起:区块链与金融科技共绘数字新世界

文章目录 一、引言二、元宇宙与区块链的深度融合三、区块链在元宇宙金融中的应用四、金融科技在元宇宙中的创新应用五、面临的挑战与机遇《区块链与金融科技》亮点内容简介获取方式 一、引言 随着科技的飞速发展&#xff0c;元宇宙概念逐渐走进人们的视野&#xff0c;成为数字…

手机备忘录可以设置密码吗 能锁屏加密的备忘录

在繁忙的生活中&#xff0c;手机备忘录成了我随身携带的“小秘书”。那些关于工作的灵感、生活的琐事&#xff0c;甚至深藏心底的小秘密&#xff0c;都被我一一记录在里面。然而&#xff0c;每次当手机离开我的视线&#xff0c;或者需要借给他人使用时&#xff0c;我总会心生担…

贝叶斯优化的门控循环神经网络BO-GRU(时序预测)的Matlab实现

贝叶斯优化的门控循环神经网络&#xff08;BO-GRU&#xff09;是一种结合了贝叶斯优化&#xff08;Bayesian Optimization, BO&#xff09;和门控循环单元&#xff08;Gated Recurrent Unit, GRU&#xff09;的模型&#xff0c;旨在进行时序预测。这种模型特别适用于时间序列数…

HTML 学习笔记(七)列表

html中的列表分为以下三种&#xff1a;有序列表&#xff0c;无序列表和自定义列表 1.有序列表 有序列表由两个元素组成&#xff1a;元素ol和元素li&#xff0c;此两个元素是父子关系&#xff0c;li必须包裹在ol里使用&#xff0c; ol里直接嵌套的只有li&#xff0c;其嵌套效果…

SpringBoot配置达梦数据库依赖(达梦8)

maven配置 <!-- 达梦数据库 --><dependency><groupId>com.dameng</groupId><artifactId>DmJdbcDriver18</artifactId><version>8.1.1.193</version></dependency><dependency><groupId>com.alibaba&l…

Day33:安全开发-JavaEE应用SQL预编译Filter过滤器Listener监听器访问控制

目录 JavaEE-预编译-SQL JavaEE-过滤器-Filter JavaEE-监听器-Listen 思维导图 Java知识点 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;序列化数据&#xff0c;身份验证&#xff0c;框架开发&#xff0c;第三方库使用等. 框架库&#xff1a;MyBatis&#…

Era Network在web3行业的价值

近年来,以比特币和以太坊为代表的区块链技术快速发展,去中心化、信任机制的创新概念也越来越受到广泛关注。AI人工智能与区块链技术在互联网应用领域的落地,正在引领互联网进入价值互联的新阶段web3.0时代&#xff01; 新行业发展的价值与优先级 WEB3行业发展的核心需求是&…

N3-Chitosan N3 叠氮修饰壳聚糖 改性叠氮 CS-Azide

碳水科技&#xff08;Tanshtech&#xff09;可以提供壳聚糖衍生物 1.壳聚糖的各种改性(NH2/COOH/SH/N3/MAL-Chitosan等) 2.各种靶向小分子修饰壳聚糖&#xff08;Biotin/FA/cRGD-Chitosan等&#xff09; 3.各种荧光标记壳聚糖(FITC/RB/CY-Chitosan等) 4.壳聚糖和各种聚合物…

机器学习的基础学习笔记

黑马的学习视频 大家常说的人工智能、机器学习、深度学习其实是包含关系&#xff0c;深度学习是机器学习的一种特殊方法&#xff0c;而机器学习又是人工智能的一个子领域。 其中机器学习是使计算机系统能够通过学习经验和数据来改进性能。机器学习算法能够从数据中发现模式&am…

sqllab第七关通关笔记

知识点&#xff1a; 利用回显信息不同进行盲注爆破出敏感信息两种绕过方法 单引号闭合绕过&#xff1b;不加注释符 id 1 and 11 完全闭合原始语句的绕过&#xff1b;这题是采用了where id((输入)) id 1)) and 11 -- 首先判断注入类型 构造id1/0 正常回显&#xff0c;字符型注…

5.Python从入门到精通—Python 运算符

5.Python从入门到精通—Python 运算符 Python 运算符算术运算符比较&#xff08;关系&#xff09;运算符赋值运算符逻辑运算符位运算符成员运算符身份运算符运算符优先级 Python 运算符 Python语言支持以下类型的运算符: 算术运算符比较&#xff08;关系&#xff09;运算符赋…

ubuntu20.04上获取Livox Avia雷达点云数据

若拿到手的Livox Avia激光雷达不知道它的ip信息&#xff0c;可以在官网上LiDAR Sensors - Livox下载上位机软件Livox Viewer&#xff0c;查看IP&#xff0c;下载window版本就可以。雷达通过网线连上电脑后&#xff0c;该软件就可以自动识别出来。按照下图步骤&#xff0c;就可以…

【计算机视觉】目标跟踪| 光流算法详细介绍|附代码

0、前言 在上篇文章中https://blog.csdn.net/Yaoyao2024/article/details/136625461?spm1001.2014.3001.5501&#xff0c;我们对目标跟踪任务和目标跟踪算法有了大致的了解。今天我们就来详细介绍一下其中的生成式算法的一种&#xff1a;光流法。 在介绍光流法之前&#xff…