-
MATLAB实现图像灰度直方图
2020-09-08 11:21:34MATLAB实现图像灰度直方图 (近期有用到灰度直方图的情况,就稍微做了一点点小总结,第一次总结,借鉴了很多博主的文章,下面会码出链接,膜拜大佬~) ...从图像灰度级的分布可以看出一幅图像的灰度(近期有用到灰度直方图的情况,就稍微做了一点点小总结,第一次总结,借鉴了很多博主的文章,下面会码出链接,膜拜大佬~)
1. 图像灰度直方图
灰度直方图是将数字图像中所有像素按灰度值的大小,统计每种像素值出现的频率。
此处以uint8类的图像为例,该类图像具有2^8=256级亮度,不同亮度对应的像素数不同,统计得到256级亮度分别对应的像素数并绘制出直观的图表,其横坐标对应灰度值(0为黑色,255为白色),纵坐标对应每种像素出现的次数。
从图像灰度级的分布可以看出一幅图像的灰度分布特性。例如,图1,2给出的是未经处理的原始图像及其对应灰度直方图:
Fig.1 原始图像
Fig.2 原始图像对应灰度直方图
如下图3,4是以调低亮度的图像(过暗图像)作为输入所对应的灰度直方图:
Fig.3 过暗图像
从图中可以看出,图3的输入图像较暗,因此其像素灰度值大多分布在较暗区域。
Fig.4 过暗图像对应灰度直方图
下图5,6是以增强亮度的图像(过亮图像)作为输入所对应的灰度直方图:
Fig.5 过亮图像
Fig.6 过亮图像对应灰度直方图
可以看出,图5的图像特性偏亮,因此其像素灰度值集中分布在亮区。2. 相关函数
主要是在提取图像灰度直方图过程中涉及的一些MATLAB函数及其部分使用方法,具体可通过文末给出的【MATLAB函数查询】链接查询。
1. imread() —— 图像读入函数A = imread(‘filename’) ;
从 filename 指定的文件读取图像,并从文件内容推断出其格式。如果 filename 为多图像文件,则 imread 读取该文件中的第一个图像。使用imread()读取图像,括号内应用引号给出图像文件的全名字符串(包括任何可用的扩展名,比如图像类型),但采用这条语句,其输入图片必须与.m文件在同一目录下(同一文件夹中),例如语句1:
f = imread('PicName.jpg');
也可读取其他文件夹中的图像,例如语句2:
f = imread('E:\matlab\2020a\cx\pic\PicName.jpg');
此处给出一组代码1,实现读取一幅图像并显示,设置标题为Pic:
close all;clear all;clc f = imread('E:\matlab\2020a\cx\pic\PicName.jpg'); % 从目标路径读入图像 figure,imshow(f);title('Pic'); % 显示图像并设置标题为Pic
Fig.7 读取并显示图像
2.rgb2gray() —— 真彩图像灰度化函数I = rgb2gray(RGB);
rgb2gray函数通过消除色调和饱和度信息,同时保留亮度,将RGB图像转换为灰度图。通过对输入的RGB图像进行灰度化处理,获取对应的灰度图像。如下给出一组代码2,实现对RGB图像的读取、灰度化、显示、并设置标题:
close all;clear all;clc f = imread('E:\matlab\2020a\cx\pic\PicName.jpg'); % 从目标路径读入图像 gray_f = rgb2gray(f); % 灰度化处理 figure, subplot(121);imshow(f);title('Org'); % 显示图像并设置标题为Org subplot(122);imshow(gray_f);title('Gray'); % 显示图像并设置标题为Gary
Fig.8 图像灰度化处理
3.imwrite() —— 图像写入函数imwrite(A,‘filename’);
将图像数据A写入filename指定的文件,并从扩展名推断出文件格式。imwrite在当前文件夹中创建新文件,输出图像的位深度取决于A的数据类型和文件格式。
imwrite(A,map,‘filename’);
将A中的索引图像及其关联的颜色图写入由 map filename 指定的文件。使用imwirte()函数将图像以指定名称及格式写入当前目录,如下代码3所示,实现将灰度处理后的图像数据命名为GrayImg,并以JPG格式存入指定目录:
close all;clear all;clc f = imread('E:\matlab\2020a\cx\pic\PicName.jpg'); % 从目标路径(E:\matlab\2020a\cx\pic)读入图像 gray_f = rgb2gray(f); % 灰度化处理 imwrite(gray_f,'E:\matlab\2020a\cx\pic\GrayImg.jpg'); % 将灰度处理后的图像数据命名为GrayImg并以JPG格式存入指定目录(E:\matlab\2020a\cx\pic)
4.imshow() —— 图像显示函数
imshow(I);
在图窗中显示灰度图像I。imshow使用图像数据类型的默认显示范围,并优化图窗、坐标区和图像对象属性以便显示图像。
imshow(‘filename’);
显示存储在由filename指定的图形文件中的图像。使用imshow()函数显示图像,如下代码4所示,实现读取图像并显示出来,设置标题为Org:
close all;clear all;clc I = imread('E:\matlab\2020a\cx\pic\PicName1.jpg'); % 从目标路径读入图像 figure, imshow(I);title('Org'); % 显示图像并设置标题为Org
5.imhist() ——绘制图像直方图函数
imhist(I) ;
绘制灰度图像I的图像直方图,可直接显示。
imhist(I,n);
指定灰度级的数目为n,n默认为256.。
[counts,x] = imhist(I);
计算灰度图像I的直方图,并返回直方图的数据(出现的灰度级与其出现次数),并通过stem(x,counts)可绘制直方图。如代码5,实现获取图像的灰度直方图:
close all;clear all;clc f = imread('E:\matlab\2020a\cx\pic\PicName.jpg'); % 从目标路径读入图像 gray_f = rgb2gray(f); % 灰度化处理 figure, subplot(121);imshow(gray_f);title('灰度图像'); subplot(122);imhist(gray_f);title('Gray Histogram'); % 绘制并显示灰度直方图
Fig.9 获取灰度直方图
代码6,实现获取图像的灰度直方图统计信息:close all;clear all;clc f = imread('E:\matlab\2020a\cx\pic\PicName.jpg'); % 从目标路径读入图像 gray_f = rgb2gray(f); % 灰度化处理 [Cot,Val] = imhist(gray_f); % 获取直方图统计信息,Val为出现的灰度值,Cot为对应灰度值出现的频数
6.histeq()——直方图均衡化函数
直方图均衡化是一种利用灰度变换自动调节图像对比度质量的方法,基本思想是通过灰度级的概率密度函数求出灰度变换函数,是一种以累计分布函数变换法为基础的直方图修正法。
在MATLAB图像处理工具箱中提供了函数histeq()进行直方图均衡化处理。J = histeq(I,n);
变换灰度图像I,返回具有n个离散灰度级的直方图均衡化后的灰度图像J,n默认为64。该变换使映射到J的n个灰度级中每个级别的像素个数大致相等,直方图大致平坦,且当n<<I中的离散灰度级数时,直方图更平坦。
J = histeq(I,hgram);
直方图规定化,hgram为一个整数向量,以使输出灰度图像J具有length(hgram)个bin的直方图近似匹配目标直方图hgram。
[J,T] = histeq(I);
返回灰度变换T,该变换将图像I中的灰度级映射到J中的灰度级。通过函数histeq()对图像进行直方图均衡化处理,其具体实现如下代码7所示:
close all;clear all;clc f = imread('E:\matlab\2020a\cx\pic\PicName.jpg'); % 从目标路径读入图像 gray_f = rgb2gray(f); % 灰度化处理 hgram = ones(1,256); J = histeq(gray_f); % 使用直方图均衡增强强度图像的对比度(默认n=64) T = histeq(gray_f,hgram); % 直方图规定化 figure, subplot(131);imshow(uint8(gray_f));title('原始灰度图像'); % 显示灰度原始图像 subplot(132);imshow(uint8(J));title('histeq均衡化结果'); % 显示均衡化后的结果图像 subplot(133);imshow(uint8(T));title('直方图规定化结果'); % 显示规定化均衡后的结果图像 figure, subplot(131);imhist(gray_f);title('灰度图像直方图'); % 显示原始图像的直方图 subplot(132);imhist(J);title('histeq均衡化直方图'); % 显示均衡化后的直方图 subplot(133);imhist(T);title('规定化均衡后直方图'); % 显示规定化均衡后的直方图
Fig.10 histeq均衡化效果图
Fig.11 均衡化后对应直方图
7.adapthisteq()——直方图均衡化函数
与histeq()函数不同,adapthisteq()的处理目标是图片的小块区域的数据,而非整幅图像的对比度增强,使输出区域的直方图大约匹配指定的直方图,相邻的小块采用双线性插值混合,以消除人工诱导的边界。J = adapthisteq(I);
使用限制对比度的自适应直方图均衡化 (CLAHE) 来变换值,从而增强灰度图像I的对比度。具体参考文末链接【MATLAB自适应直方图均衡—adapthisteq】。
如下给出一组代码8,实现采用adapthisteq()对图像灰度直方图的均衡化处理:close all;clear all;clc f = imread('E:\matlab\2020a\cx\pic\PicName.jpg'); % 从目标路径读入图像 gray_f = rgb2gray(f); % 灰度化处理 F = adapthisteq(gray_f); % adapthisteq均衡后的直方图 figure, subplot(221);imshow(gray_f);title('灰度图像'); subplot(222);imshow(F);title('均衡化后图像'); % adapthisteq均衡后效果图 subplot(223);imhist(gray_f);title('Gray Histogram'); % 绘制并显示灰度直方图 subplot(224);imhist(F);title('Histogram Equalization'); % 绘制并显示均衡化后的灰度直方图
Fig.12 adapthisteq均衡化效果图
8.imadjust()——图像灰度值调整函数
J = imadjust(I);
对图像I进行灰度调整。将灰度图像I中的强度值映射到J中的新值,默认对所有像素值中最低的1%和最高的1%进行饱和处理,提高输出图像J的对比度。
J = imadjust(I,[low_in high_in]);
[low_in high_in]为原图像中要变换的灰度范围。该处理将I中的强度值映射到J中的新值,使low_in和high_in之间的值映射到0到1之间的值。
J = imadjust(I,[low_in high_in],[low_out high_out]);
[low_in high_in]为原图像中要变换的灰度范围,[low_out high_out]为变换后的灰度范围。该处理将I中的强度值映射到J中的新值,使low_in和high_in之间的值映射到low_out到high_out之间的值。
J = imadjust(I,[low_in high_in],[low_out high_out],gamma);
将I中的强度值映射到J中的新值,其中gamma为映射方式,指定了描述I和J中的值之间关系的曲线形状,默认值为1,即线性映射,当gamma≠1时为非线性映射
RGB2 = imadjust(RGB1,[low_in high_in],___);
对彩色图像RGB1进行调整。将真彩色图像RGB1中的值映射到J中的新值,可为每个颜色通道应用相同的映射或互不相同的映射。通过imadjust()函数调整灰度范围,给出的原图像的灰度范围为0~255,设置待变换的范围为[0.2 0.5],变换后的范围为[0 1],即将小于51(=255×0.2)的灰度值设置为0,将大于127.5(=255×0.5)的灰度值设置为255。
其中,可通过参数gamma调整图像亮度,若gamma<1,加强亮色值输出;gamma>1,加强暗色值输出。
具体实现如下代码9所示:close all;clear all;clc f = imread('E:\matlab\2020a\cx\pic\PicName.jpg'); % 从目标路径读入图像 gray_f = rgb2gray(f); % 灰度化处理 J = imadjust(gray_f); % 默认调整灰度值 T = imadjust(gray_f,[0.2 0.5],[0 1]); % 调整灰度值 G = imadjust(gray_f,[0.2 0.5],[0 1],0.4); % 调整灰度值并提高亮度 D = imadjust(gray_f,[0.2 0.5],[0 1],4); % 调整灰度值并降低亮度 figure, subplot(231);imshow(f);title('原图'); subplot(232);imshow(gray_f);title('灰度图像'); subplot(233);imshow(J);title('默认调整后效果图'); subplot(234);imshow(T);title('调整灰度值范围效果图'); subplot(235);imshow(G);title('调整灰度值范围并提高亮度效果图'); subplot(236);imshow(D);title('调整灰度值范围并降低亮度效果图'); figure, subplot(231);imhist(gray_f);title('灰度图像直方图'); subplot(232);imhist(J);title('默认调整后直方图'); subplot(233);imhist(T);title('调整灰度值范围直方图'); subplot(234);imhist(G);title('调整灰度值范围并提高亮度直方图'); subplot(235);imhist(D);title('调整灰度值范围并降低亮度直方图');
Fig.13 adapthisteq均衡化效果图
Fig.14 均衡化后对应直方图
上述6~8函数均能够实现增强图像对比度,具体内容参考文末给出的【对比度增强方法】链接。3. 代码实现与结果
MATLAB实现对目标图像灰度化处理,计算并显示其灰度直方图,后分别采用histeq()、adapthisteq()、imajust()函数处理原灰度图像,计算并显示其灰度直方图。
% Gray histogram Test Function close all;clear all;clc %% 1.读入图像:打开指定路径图片 f = imread('E:\matlab\2020a\cx\Bookei\Gray histogram\pic\nor.jpg'); % 读图 %% 2.灰度化 gray_f = rgb2gray(f); % 灰度化处理 %% 3.保存图片 imwrite(gray_f,'E:\matlab\2020a\cx\fuzhuang\paper\Gray histogram\pic\11.jpg'); %% 4.读取图片信息(可要可不要) info = imfinfo('E:\matlab\2020a\cx\fuzhuang\paper\Gray histogram\pic\11.jpg'); %% 5.histeq均衡化处理(默认n=64) R1 = histeq(gray_f); % 使用直方图均衡增强灰度图像的对比度 %% 6.adapthisteq均衡化处理 R2 = adapthisteq(gray_f); % adapthisteq均衡后的直方图 %% 7.imadjust灰度范围调整 R3 = imadjust(gray_f,[0.2 0.5],[0 1]); % 调整灰度值 %% 8.效果图显示 figure, subplot(231);imshow(f);title('原图'); subplot(232);imshow(gray_f);title('灰度图像'); subplot(233);imshow(R1);title('histeq均衡化结果图(默认n=64)'); subplot(234);imshow(R2);title('adapthisteq均衡化结果图'); subplot(235);imshow(R3);title('imadjust灰度范围调整结果图'); %% 9.直方图显示 figure, subplot(221);imhist(gray_f);title('Gray Histogram'); % 绘制并显示灰度直方图 subplot(222);imhist(R1);title('histeq均衡化直方图'); % 显示histeq均衡化后的直方图 subplot(223);imhist(R2);title('adapthisteq均衡化直方图'); % 显示adapthisteq均衡化后的直方图 subplot(224);imhist(R3);title('imadjust灰度范围调整后直方图'); % 显示imadjust灰度范围调整后的直方图
Fig.15 效果图显示
Fig.16 直方图显示
除了能用函数imhist绘制直方图以外,还能使用函数bar、stem、plot绘制图像的直方图,具体参考文末【Matlab中imhist函数的使用及图像直方图的概念】链接。MATLAB函数查询
参考源:
Matlab图像处理转灰度图,绘制直方图,直方图均衡化
MATLAB自适应直方图均衡—adapthisteq
对比度增强方法
Matlab中imhist函数的使用及图像直方图的概念 -
记录五 图像处理之局部直方图处理
2020-06-20 12:41:20局部直方图处理的用途 如果我们要谈论局部直方图处理,那么不得不提起与之相...这里可以看出在一般情况下全局直方图均衡处理的确可以提升图像的动态范围和对比度,但是在某一些情况下则不同,请看下面这个例子,原图是局部直方图处理的用途
如果我们要谈论局部直方图处理,那么不得不提起与之相对应的全局直方图处理,之前写过一篇文章关于全局直方图处理的,对全局直方图不熟悉的话可以先去看一下,这样再看局部直方图处理会更好。记录一Opencv 和 C++实现全局直方图均衡化(原理到实践)
当我想让一幅图想的动态范围提高,提升图像的对比度我们可以采取全局直方图均衡化来处理图像,通常来说也会获得不错的结果。如下图所示
全局直方图均衡化处理前
全局直方图均衡化处理后
这里可以看出在一般情况下全局直方图均衡处理的确可以提升图像的动态范围和对比度,但是在某一些情况下则不同,请看下面这个例子,原图是一副小行星的图片,图像中心亮度很高,但四周绝大部分区域亮度很低,这时如果仍然使用全局直方图均衡化处理图像,获得的结果往往不尽人意。
原图
处理后
可以看出由于图像的动态范围被强行提升后整幅图像出现了严重失真,噪点被放大,图像细节丢失。此时使用局部的直方图处理结果会好很多。如下图所示。
原图
处理后
可以看出使用局部直方图处理后的图像还原了一部分原图中看不到的暗部细节,但是图像仍然有割裂感(在明暗交界处),一部分原因是调参的问题,选取的模板尺寸和方差系数以及均值系数有关(这幅图大概调了一下,没有细调)。
以上关于全局直方图均衡化的处理和局部直方图处理的两个实验说明的各自所适用的领域。接下来进入正题,讨论局部直方图处理。
局部直方图处理
处理的基本思想是利用大小不同的模板在图像中滑动比较整幅图像的均值和方差与局部模板(块)的均值和方差进行比较,如果符合要求就将模板中心选择为合适的候选点,将候选点的亮度乘一个常数E。但是为什么是均值和方差呢?一副图像的亮度均值反应图像的平均亮度,方差则反应图像的整体对比度,方差越大,对比度也就越强。
数学部分
上述部分介绍了了利用局部直方图信息处理图像的一种方法,接下我们看一下相关的数学公式,关于如何计算图像的方差和均值。
图像均值公式
公式一
图像方差公式
公式二
公式中的L-1中L是图像的灰阶等级数或者是亮度等级数如果是8位的图像L是256,ri是亮度等级p(ri)是当前亮度等级占全图的比例,或者是ri出现的概率。其中p(ri)可以从图像的直方图中获取到。
通过以上两个公式我们就可以获取到全局图像和局部模板的均值和方差,接下来就是如何确定候选点的问题了。
公式三
其中msxy是模板均值,mg是全局均值,sigma_sxy是局部方差,sigma_G是全局方差,计算方式由公式一二给出。k0,k1,k2是我们在处理图像过程中可调的参数,k0<1,k1<k2<0,k1是为了防止对均匀部分(方差为0)的图像部分进行增强。
代码实现
#include<opencv.hpp> #include<iostream> using namespace cv; using namespace std ; Mat src,gray,dst; void global_equalization(Mat &img); void Local_equalization(Mat &img, int size = 95, float k0 = 0.99, float k1 = 0.001, float k2 = 0.7, float E = 6); int main(int argc, char *argv[]) { src =imread("/home/qinzihang/opencv/samples/data/stone.jpg"); //resize(src, src, Size(200,200)); cvtColor(src, gray,COLOR_BGR2GRAY); cvtColor(src, src,COLOR_BGR2GRAY); imshow("GG",src); Mat test = gray; global_equalization(src); Local_equalization(gray); waitKey(0); } void global_equalization(Mat &img) { float gray_l[256] = {0}; float HI[256] = {0};//图像亮度密度1/N*h(I) float CDF[256] = {0};//累积分布函数 int rows=img.rows; int cols=img.cols; Mat draw_mat = Mat::zeros(600,600,CV_8U); float m = 0; float variance = 0; cout << rows << endl;//x for(int i=0; i<rows; i++) { for(int j=0; j<cols; j++) { uchar t; if(img.channels()==1) { t=img.at<uchar>(i,j); gray_l[t]++;//获得图像亮度信息 } } } for(int i = 0; i <256; i++) { line(draw_mat,Point(i+150,600-1),Point(i+150, 600-gray_l[i]),254); imshow("draw", draw_mat); HI[i] = (gray_l[i]/(img.cols*img.rows*1.0f));//获得密度概率 //cout << HI[i] << endl; m += HI[i]*i; } for(int i = 0; i < 256; i++) { variance += (i - m) *(i - m)*HI[i]; } for(int i = 0; i < 255; i++) { if(i == 0) { CDF[0] = HI[ 0]; } else { CDF[i] = (CDF[i-1] +HI[i]);//C(I) = C(I - 1 ) +h(I) //cout << CDF[i] << endl; } } for(int i=0; i<rows; i++) { for(int j=0; j<cols; j++) { uchar t; if(img.channels()==1) { t=img.at<uchar>(i,j); img.at<uchar>(i,j) = 255*CDF[t];//完成图像重映射至0-255 } } draw_mat = Mat::zeros(600,600,CV_8U); } imshow("yes",img); } void Local_equalization(Mat &img, int size , float k0 , float k1 , float k2, float E) { int gray_l[256] = {0}; float HI[256] = {0};//图像亮度密度1/N*h(I) float CDF[256] = {0};//累积分布函数 int rows=img.rows; int cols=img.cols; Mat draw_mat = Mat::zeros(600,600,CV_8U); float global_m = 0; float global_variance = 0; int border_x = size/2; int border_y = size/2; cout << rows << endl;//x for(int i=0; i<rows; i++) { for(int j=0; j<cols; j++) { uchar t; if(img.channels()==1) { t=img.at<uchar>(i,j); gray_l[t]++;//获得图像亮度信息 } } } for(int i = 0; i <256; i++) { HI[i] = (gray_l[i]/(img.cols*img.rows*1.0f));//获得密度概率 global_m += HI[i]*i; } cout << "global_m = " << global_m << endl; for(int i = 0; i < 256; i++) { global_variance += (i - global_m) *(i - global_m)*HI[i]; } cout << "global_variance = " << global_variance << endl; for(int i=0; i<rows - border_x; i++) { for(int j=0; j<cols - border_y; j++) { Point center_pix = Point(j+ border_x, i + border_y); int local_gray_l[256] = {0}; float local_m = 0; float local_variance = 0; float local_HI[256] = {0}; for(int M=0; M<size; M++) { for(int N=0; N<size; N++) { uchar t; t=img.at<uchar>(i + M, j + N); local_gray_l[t]++; } } for(int k = 0; k <256; k++) { local_HI[k] = (local_gray_l[k]/(size*size*1.0f));//获得密度概率 local_m += local_HI[k]*k; } // cout << "local_m = " << local_m << endl; for(int k = 0; k < 256; k++) { local_variance += (k - local_m) *(k - local_m)*local_HI[k]; } // cout << "local_variance = " << local_variance << endl; if( local_m < global_m*k0 && (k1 * global_variance < local_variance && local_variance < k2 * global_variance)) { if(E * img.at<uchar>(center_pix) < 255) { img.at<uchar>(center_pix) = E * img.at<uchar>(center_pix); //cout << "new_pix = " << E * img.at<uchar>(center_pix) << endl; } else { img.at<uchar>(center_pix) = 255; } } } } imshow("loacl",img); }
这部分代码实现和之前的全局直方图均衡类似,也很简单,如果有看不懂的可以留言或者去看一下以下两篇。
记录一Opencv 和 C++实现全局直方图均衡化(原理到实践)
以上便是本文的所有内容,如有错误疏漏欢迎大家指出.
-
基于自适应加权Curvelet梯度方向直方图的人脸识别算法
2021-01-26 06:20:11然后按照编码方式将同一尺度下不同方向的特征进行编码融合,获得融合后的幅值域图谱,并通过HOG算子结合分块的方法获得Curvelet变换后融合图像的直方图特征,分别根据每个尺度对人脸识别率的贡献进行计算,得出各尺度的... -
3D4U和PSDTO3D立体图像制作教程
2010-12-19 05:03:254、以上几种效果在一幅图像中的综合运用:用PSDTO3D软件伏做图,可以使立体、变画、动画、旋转、缩放等特殊效果同时在一幅画面中体现,具体做法是用上述方法分别做好各种效果,进行分组链接即可。 5、“文件”菜单... -
UNet是医学图像处理方面著名的图像分割网络,过程是这样的:输入是一幅图,输出是目标的分割结果。继续简化就是,一幅图,编码,或者说降采样,然后解码,也就是升采样,然后输出一个分割结果。根据结果和真实分割的...
-
HTTP之头部过长和非80端口的报文分析
2016-01-22 17:12:54情况一: ...从这幅图可以看出两点:1,不同的颜色表示协议。2,String那一栏表示的是针对该种协议的规则(即wireshark是根据什么条件来判断该报文是什么协议的报文,当然你可以添加新的协议本文对抓包过程中遇到的两种情况做了简单的分析:1,HTTP使用非80端口;2,HTTP头部过长导致头部分包传输。
情况一:
在wireshark的view->Coloring Rules里面有这个界面。从这幅图可以看出两点:1,不同的颜色表示协议。2,String那一栏表示的是针对该种协议的规则(即wireshark是根据什么条件来判断该报文是什么协议的报文,当然你可以添加新的协议和规则)。有什么用处的,看如下的图:
这是一条使用HTTP协议的流,wirshark将其标记为TCP。经过分析不难发现wireshark中使用TCP的80端口来识别HTTP协议,而图中的流虽然使用的是HTTP协议,但是并没有使用80端口而是使用1028端口,因此wireshark将按照IP层的协议字段将其识别为TCP。但是分析的时候,我们应该尽可能的定位其具体的应用层协议。我们应该知道,这是一条HTTP流,将其改为HTTP的方法是选中无法识别的报文->右键单击->Decode As->选择相应的应用层协议(当然这也仅仅是为了方便看,这是需要注意的一点),如下图:
以上的现象是我们联想到了一个问题,即底层的协议是如何承载上层的协议的:在数据链路层,使用两个字节的类型字段表示后续数据类型,比如TYPE:IP(0x0800);在IP层有专门的8为协议字段表示上层的协议,比如TCP为6;在运输层并没有这样一个协议字段,而是用熟知的端口号来表示协议,SSL为443。这几种方式还是有一定的差异的(我的意思是为什么各层为什么不统一一下,明显端口号增加了应用层协议设计的灵活度)。
看第二种情况
提一下前面三个握手包中的长度字段。数据是在以太网上跑的,以太网要求数据范围是46-1500,因此数据部分不足46的要使用padding字段来填充,在第三个握手包中,就出现了6字节填充的情况。因此在使用wireshark抓以太网包的时候最小长度为60=14(以太网头)+6(填充)+20(IP最小)+20(TCP最小),但是你可能会说你的包中存在54个字节的情况,这是什么原因呢?下面的红色解释是转自CSDN, 具有一定的参考价值:
根据rfc894的说明,以太网封装IP数据包的最大长度是1500字节,也就是说以太网最大帧长应该是以太网首部加上1500,再加上7字节的前导同步码和1字节的帧开始定界符,具体就是:7字节前导同步码 + 1字节帧开始定界符 + 6字节的目的MAC + 6字节的源MAC + 2字节的帧类型 +1500 + 4字节的FCS。按照上述,最大帧应该是1526字节,但是实际上我们抓包得到的最大帧是1514字节,为什么不是1526字节呢?原因是当数据帧到达网卡时,在物理层上网卡要先去掉前导同步码和帧开始定界符,然后对帧进行CRC检验,如果帧校验和出错,就丢弃此帧。如果校验和正确,就判断帧的目的硬件地址是否符合自己的接收条件(目的地址是自己的物理硬件地址、广播地址、可接收的多播硬件地址等),如果符合,就将帧交给“设备驱动程序”做进一步处理。这时我们抓包的软件才能抓到数据,因此,抓包软件抓到的是去掉前导同步码、帧开始分界符、FCS之外的数据,其最大值是6 + 6 + 2 + 1500 = 1514。
以太网规定,以太网帧数据域部分最小为46字节,也就是以太网帧最小是 6 + 6 + 2 + 46 + 4 = 64。除去4个字节的FCS,因此,抓包时就是60字节。当数据字段的长度小于46字节时,MAC子层就会在数据字段的后面填充以满足数据帧长不小于64 字节。由于填充数据是由MAC子层负责,也就是设备驱动程序。不同的抓包程序和设备驱动程序所处的优先层次可能不同,抓包程序的优先级可能比设备驱动程序更高,也就是说,我们的抓包程序可能在设备驱动程序还没有填充不到64字节帧的时候,已经捕获了数据。因此不同的抓包工具抓到的数据帧的大小可能不同。(比如,wireshark抓到的可能没有填充数据段,而sniffer抓到的就有填充数据段),(不过根据我的观察wireshark不同的版本抓获的最小数据包的大小好像有60字节也有54字节的情况.....)。
上述的解释我是部分赞同的,但是对于小于54个字节的包,我的理解和上述还是有点差异的。我在抓包的过程中发现,基本都是下行的包。也就是说上行出去的包,由于优先级关系,填充完毕之后才被捕获;对于下行进来的包,同样的优先级关系,驱动程序会不会去除了填充的部分,然后才被我们抓包软件捕获呢?我觉得我的想法有一定的合理性。(PS:关于winpcap是如何捕获数据的可以参考《原理、实践与WinPcap深入解析》)
我们姑且认为60-1514是正确的数据范围,因为我们这次讨论的问题与长度关,但是长度只是个引子。首先整个颜色是绿色,还记得我们第一种情况中所提到的情况,wireshark的识别HTTP的原则即端口为80的情况,因此整条流为HTTP流。再看我们包中的数据,第4,5个包,好像与我们通常遇到的情况有所不同。正常情况下,我们所遇到的都是3个握手包之后跟上HTTP的协议请求,为什么这次握手包之后跟上的是分段的包。经过查看包中的数据发现,造成这种情况的原因是GET请求中的URL过长,超过了以太网所能承载的最大数据长度,或者确切的说是超过了TCP所能承载的最大数据长度即1500-20-20=1460,因此需要分段传输。而不巧的是,由于分段将UA的值部分分成了两个部分,那么如果出现这种情况,对于绝大多数的协议识别系统来说,如果该流是简单的基于UA识别,那么将造成识别不了的情况。因为绝大多数的系统并没有类似这种情况的报文重组考虑进去。
上述的过程中存在着一个问题那就是第4个包为什么被识别成为TCP而第五个包被识别成为HTTP,我是没有想明白(会不会是wireshark解释器的bug),因为并没有研究过wireshark的解释器。以后有机会研究一下,如果哪位大神知道,也请告知一下。还有就是文中有可能会有地方说的不太对,也请指出来。
-
Linux pthread_create多线程创建耗时不同?
2017-05-26 13:12:17而对于28*28的每一个线程的卷积时间也就是200左右(单位相同),四个线程(NUM = 4)加起来900左右,所以可以看出线程创建中每一张图都有一个线程占用了相当于总处理时间的时间,32*32*3和256*256*3的线程创建时间也... -
计算机视觉系列教程 (二)卷积与滤波详解
2018-07-03 18:19:41什么是滤波? 要了解什么是滤波,首先要知道什么是波。...引用一幅图 会看的更加清楚http://blog.jobbole.com/70549/ 从这幅图中可以看出来,图像其实是由不同频率的波长组成的,存在着高... -
2017-2018 ACM-ICPC, Asia Daejeon Regional Contest F(递推)
2018-02-10 16:22:00看上图很容易便可以看出规律,每幅图都是由上一幅图在自身的四个区域进行不同的变化的到的,如第二幅图中,第一区域是第一副图向左转90度得到的,第二第三区域都是横纵坐标偏移,第四区域是向右转90度且向右移动了一... -
Java线程:线程栈模型与线程的变量
2015-09-05 17:35:38这幅图描述在代码执行到两个不同时刻1、2时候,虚拟机线程调用栈示意图。 当程序执行到t.start();时候,程序多出一个分支(增加了一个调用栈B),这样,栈A、栈B并行执行。 从这里就可以看出方法调用和线程... -
交互动画和组件.pptx
2020-01-25 00:36:0411.1.1 学习目标 时区时钟动画播放后4个模拟指针钟在不停地转动可以看出它们指示的时间是不一样的好像宾馆中的不同时区的不同时钟一样另外这些模拟指针钟的颜色也不相同该动画播放后的一幅画面如图11-1-1所示;图11-1... -
CMOS基本知识整理
2020-04-09 17:22:53从这幅图可以看出,或者存在潜在的几个信息 首先看版图中间上方注明了每个颜色区域代表的内容。红色为栅极-多晶硅(也可以为金属),绿色为源漏区–扩散层,蓝色为互连线金属铝,背景色为Nx型衬底,白色虚线区域为P型... -
特征选择
2017-11-21 12:02:20特征选择 1.相关性 通过使用相关性,我们很容易看到...下面每幅图上方的相关系数Cor(X1, X2)是计算出来的皮尔逊r值,从图中可以看出不同程度的相关性。 p值越高,我们越不能信任这个相关系数 上图 -
特征选择的两种方法
2018-08-14 22:10:421.相关性 ...下面每幅图上方的相关系数Cor(X1, X2)是计算出来的皮尔逊r值,从图中可以看出不同程度的相关性。 p值越高,我们越不能信任这个相关系数 上图中,前三个具有高相关系数,我们可以选择把X... -
如何理解概率论中的“矩”?
2020-11-18 10:50:21大家应该都知道物理中的力矩,我这里也不展开说细节了,用一幅图来帮助大家回忆一下: 上图中,两边能保持平衡,只要满足下面的式子就可以了(很粗糙的式子,没把力作为向量来考虑): 其中,都称为力矩。 ... -
Ext4.1grid单元格合并的解决方案
2013-10-24 10:46:29从这幅图可以看出,该合并的都合并了,不该合并的也合并了,第三列“A单元”,属于不同的地块,不同栋数,常理是不应该合并的,所以引出一个问题,合并列时应该判断前一列的合并情况,属于不同合并区的单元格虽然值... -
JSP内置对象——session对象
2019-10-01 20:09:15举个购物流程的例子: 这整个购物过程,它是...从图中可以看出,我们的session是保存在服务器当中的,保存着3个session,这三个session对象跟用户客户端是以一一对应的。 接下来再看一下session对象的一些相关... -
C#识别简单的验证码(上)
2015-08-09 16:20:15需要说明的是,这篇文章所讲的方法只适应于识别某一种特定的验证码,并不具有普遍性,但是读者可以参考其中的思维过程。 下面是我们要识别的验证码的样本: ...这一点从第二幅图中的3以及第四幅图中的L可以看出 -
调用登录_微信小程序登录逻辑梳理(有源码)
2021-01-12 19:49:45小程序登录的逻辑和平常app的登录逻辑不同,下面用一幅图来说明:app 登录逻辑:微信小程序 登录逻辑:从上图中可以看出,小程序需要作一系列判断才能走到,请求自己公司后台接口登录这步骤.附下源码,包括登录前 检查本地 ... -
sa登录失败_微信小程序登录逻辑梳理(有源码)
2020-12-04 14:35:53小程序登录的逻辑和平常app的登录逻辑不同,下面用一幅图来说明:app 登录逻辑:微信小程序 登录逻辑:从上图中可以看出,小程序需要作一系列判断才能走到,请求自己公司后台接口登录这步骤.附下源码,包括登录前 检查本地 ... -
停车坐看枫林晚
2019-04-03 10:48:00即使你是一个新手,初次登录Bing主页后,也立刻能看出她与其它搜索引擎网站最大的不同,那就是她善变的衣着----每天更换的一幅大图片。 上线后的几天,用户的反馈声不绝于耳: “我每次都要等待图片下载完毕,... -
特征选择-皮尔逊相关系数-互信息
2020-10-01 16:36:04下面每幅图上方的相关系数Cor(X1, X2)是计算出来的皮尔逊r值,从图中可以看出不同程度的相关性。 scipy.stats.pearsonr(),给定两个数据序列 ,会返回相关系数值和p值所组成的元组。皮尔逊相关系数(皮尔逊r值)... -
xnor net
2019-07-04 14:16:59网络最后一层,BN前后activation均值方差随训练次数的变化 固定样本点,也就是采用了相同的数据集子集(因为没必要囊括全部样本点),...从上图可以看出,随着训练次数增加,BN前的均值会大幅上涨,会有一个区间增... -
Java各种数据结构使用原则(总结自thinkinJava)
2011-06-16 04:58:00从早些时候的那幅示意图可以看出,实际上只有三个集合组件:Map,List和Set。而且每个接口只有两种或三种实施方案。若需使用由一个特定的接口提供的功能,如何才能决定到底采取哪一种方案呢?为理解这个问题,必须... -
集合类的使用
2007-03-26 17:06:00从早些时候的那幅示意图可以看出,实际上只有三个集合组件:Map,List和Set。而且每个接口只有两种或三种实施方案。若需使用由一个特定的接口提供的功能,如何才能决定到底采取哪一种方案呢?为理解这个问题,必须... -
停车坐爱枫林晚
2015-05-15 12:09:00即使你是一个新手,初次登录Bing主页后,也立刻能看出她与其它搜索引擎网站最大的不同,那就是她善变的衣着----每天更换的一幅大图片。 上线后的几天,用户的反馈声不绝于耳: “我每次都要等待图片下载完毕,才能...