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

标题:基于自适应阈值与K-means聚类的图像行列排序与拼接处理

摘要:

本文提出了一种基于自适应阈值和K-means聚类的图像行列排序与拼接方法。通过对灰度图像的自适应二值化处理,计算并分析图像的左右边距,从而确定图像的行数与列数。通过对图像进行特征提取,并使用K-means聚类进行排序,再结合行列拼接技术,成功实现了图像的排序与拼接。最终输出了按行列排序后的图像,为图像分析及处理提供了新的方法。

关键词:图像处理、K-means聚类、自适应阈值、图像排序、图像拼接
 

在本项目中,我们使用了多个Python库来实现图像处理、图像加载、阈值化、拼接以及最终结果保存。每个库的功能及其在项目中的作用如下所述:

1. OpenCV (cv2)

功能介绍: OpenCV(Open Source Computer Vision Library)是一个广泛使用的计算机视觉库,提供了丰富的图像处理函数。它支持包括图像处理、物体识别、图像分割、视频处理等多个领域。

在本项目中的作用: 我们使用cv2库中的adaptiveThreshold函数来对灰度图像进行自适应阈值处理。自适应阈值处理是根据局部区域的均值来动态调整阈值,能够更好地处理图像中的细节,尤其是当图像中的光照条件不均匀时。

  • adaptiveThreshold:实现自适应阈值化。
  • maxValue=1:二值化后的像素值设定为1(白色)。
  • adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C:自适应方法,基于邻域区域均值计算阈值。
  • blockSize=11:计算每个区域均值的方块大小。
  • C=1:常数项,从每个区域均值中减去的常量,用于微调阈值。

2. NumPy

功能介绍: NumPy是一个强大的数值计算库,提供了高效的多维数组操作及线性代数运算功能。它是进行数值计算和数据分析时的基础库之一。

在本项目中的作用: 我们使用NumPy来处理和存储图像数据。图像读取后被转换为NumPy数组,这使得我们能够高效地操作图像的像素值,如在进行自适应阈值处理时,使用数组操作来获取图像的每个像素值。此外,NumPy的hstack函数用于将多个图像按水平排列拼接。

  • np.asarray:将图像集合转换为NumPy数组。
  • np.hstack:按水平方向拼接图像。

3. scikit-image (skimage)

功能介绍: scikit-image是一个专门用于图像处理的Python库,它构建于SciPy之上,提供了各种图像处理工具,如滤波、图像分割、特征提取等。

在本项目中的作用: 我们使用skimage.io中的ImageCollection方法加载灰度图像,并将其转换为一个可操作的集合。这使得我们能够读取指定目录下的所有图像文件,并将它们加载为图像数组。

  • io.ImageCollection:用于加载指定路径下的所有图像,返回一个包含所有图像的集合对象。

4. Pillow (PIL)

功能介绍: Pillow是Python Imaging Library(PIL)的一个分支,提供了图像处理功能,如打开、编辑和保存各种格式的图像。

在本项目中的作用: 我们使用Pillow中的Image.fromarray函数将拼接后的图像(NumPy数组)转换为Pillow图像对象,并将最终的图像保存为PNG格式。该库简化了图像的保存过程,使得结果能够以不同的格式输出。

  • Image.fromarray:将NumPy数组转换为Pillow图像对象。
  • im.save:将图像保存为指定格式(如PNG)。

5. collections.Counter

功能介绍: collections.Counter是一个用于计数的字典子类,它可以用来统计元素的频率,提供了非常高效的计数功能。

在本项目中的作用: 在拼接过程中,我们需要确保每张图像只被选中一次。Counter帮助我们追踪哪些图像已经被添加到最终的排序列表中,避免重复选择。

  • ans_index.count(i):统计某个图像索引在ans_index列表中的出现次数,用于判断是否已经选择过该图像。

python

if(ans_index.count(i) == 1):continue

python

im = Image.fromarray(ans_img)  # 转为Image对象
im.save('result1.png')  # 保存拼接后的图像

python

import skimage.io as io
coll = io.ImageCollection(path)  # 读入灰度图像

python

plt.imshow(ans_img, cmap='gray')  # 显示拼接后的图像
plt.show()

python

img = np.asarray(coll)  # 将图像集合转换为NumPy数组
ans_img = np.hstack((ans_img, coll[ans_index[i]]))  # 水平拼接图像

python

img[i] = cv2.adaptiveThreshold(src=img[i],maxValue=1,adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C,thresholdType=cv2.THRESH_BINARY,blockSize=11,C=1
)

对于问题1:

1.1 数据预处理

首先,我们加载包含若干灰度图像的文件夹,并将它们读取为一个图像集。以下代码通过skimage.io库中的ImageCollection方法加载图像:

python

data_dir = './附件1'
path = data_dir + '/*.bmp'
coll = io.ImageCollection(path)  # 读入灰度图像
img_num = len(coll)

coll是一个包含所有灰度图像的对象,每一张图像都以numpy数组的形式存储在其中。img_num记录了图像的数量。

1.2 图像预处理:自适应阈值

在图像拼接的过程中,为了增强图像中的边缘信息,我们对每张图像进行自适应阈值处理。自适应阈值方法是一种局部阈值化方法,它根据每个局部区域的平均值来确定阈值,而不是全局阈值。

python

img = np.asarray(coll)
for i in range(0, len(coll)):img[i] = cv2.adaptiveThreshold(src=img[i],maxValue=1,adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C,thresholdType=cv2.THRESH_BINARY,blockSize=11,C=1)

在上述代码中,我们使用了cv2.adaptiveThreshold函数来对每张图像进行二值化处理。maxValue=1表示将阈值处理后的值设置为1,adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C表示每个像素的阈值是其邻域区域均值,blockSize=11设定了区域的大小,C=1是一个常数,用来调整阈值。

1.3 计算左边缘的匹配度

在完成了自适应阈值化后,下一步是计算每张图像的左边缘与其他图像左边缘的匹配度。我们选择一个参考图像,并根据其左边缘的像素值与其他图像的左边缘进行比较,找到与之最匹配的图像。

python

Max = -1
index = 0
for i in range(0, img.shape[0]):count = 0for y in range(0, img.shape[2]):panduan = 1for x in range(0, img.shape[1]):if(img[i][x][y] == 0):panduan = 0breakif(panduan == 1):count = count + 1else:breakif(count > Max):Max = countindex = i

在这段代码中,我们遍历所有图像并计算其左边缘的匹配度。我们通过检测每一列的像素值是否为0(即图像的非背景区域)来判定其边缘的连续性。count记录了与参考图像左边缘匹配的连续像素点数,Max用于记录最大匹配值,index记录最匹配的图像索引。

1.4 边缘匹配:右边缘匹配

为了找到最佳的图像顺序,我们不仅需要左边缘匹配,还需要右边缘匹配。我们通过比较当前图像的右边缘与已选择图像的左边缘之间的匹配度来选出最匹配的图像。

python

ans_index = []
ans_index.append(index)  # 插入第一张图片的索引while(1):Max = -1index = 0zj = ans_index[len(ans_index)-1]for i in range(0, len(coll)):if(ans_index.count(i) == 1):continuecount = 0for x in range(0, img.shape[1]):if(img[i][x][0] == img[zj][x][img.shape[2]-1]):count = count + 1if(count > Max):Max = countindex = ians_index.append(index)if(len(ans_index) == len(coll)):break

在这个部分,我们为每个已选图像找到与之最匹配的图像。通过计算右边缘与左边缘的匹配度,逐步拼接图像,直到所有图像都被选出并排序完毕。

1.5 拼接图像

最后,我们将所有匹配的图像按照顺序拼接成一张完整的图像。通过np.hstack函数将图像按列进行合并:

python

ans_img = coll[ans_index[0]]
for i in range(0, len(ans_index)):if(i == 0):continueans_img = np.hstack((ans_img, coll[ans_index[i]]))  # 水平合并

这里,我们使用np.hstack将所有选定的图像按顺序拼接成一张大图,最终形成一个完整的拼接图像。

1.6 结果保存

最后,我们将拼接完成的图像保存为PNG格式:

im = Image.fromarray(ans_img)  # 转为Image对象
im.save('result1.png')

对于附件2只需将导入的地址修改为附件2即可

对于附件3:

2.1 图像读取与自适应阈值处理

首先,利用skimage库中的ImageCollection方法读取图像,并将每个图像进行自适应阈值处理。自适应阈值方法采用了ADAPTIVE_THRESH_MEAN_C,它根据局部区域的均值计算阈值,从而有效地提高图像的二值化效果。

python

img[i] = cv2.adaptiveThreshold(src=img[i],maxValue=1,adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C,thresholdType=cv2.THRESH_BINARY,blockSize=11,C=1)
2.2 计算左右边距与确定图像行列数

通过计算每张图像的左右边距,进一步推测图像的行数与列数。边距的计算方法依赖于图像每行的0值与非0值分布,最终得出图像的行列数为11行和19列。

2.3 聚类与排序

对图像进行特征提取后,使用K-means聚类算法对图像进行排序。通过聚类结果,确定每一类图像的顺序,从而为图像拼接提供排序依据。

python

kmeansmodel = KMeans(n_clusters=11, init='k-means++')
y_kmeans = kmeansmodel.fit_predict(x_train)
2.4 图像拼接

基于行列排序,进行图像的行拼接和列拼接。首先,将按行排序后的图像合并,形成按行排列的图像矩阵。接着,再对行进行竖向拼接,完成图像的最终拼接。

python

ans_img = ans_hang_img[lie_index[0]]
for i in range(1, len(lie_index)):ans_img = np.vstack((ans_img, ans_hang_img[lie_index[i]]))  # 按照新的顺序进行竖向拼接

首次聚类(无人工干预)

[7, 208, 138, 158, 126, 68, 175, 45, 174, 0, 137, 53, 56, 93, 153, 70, 166, 32, 196]

[14, 128, 3, 159, 82, 199, 135, 12, 73, 160, 203, 169, 134, 39, 31, 51, 107, 115, 176]

[29, 64, 111, 201, 5, 92, 180, 48, 37, 75, 55, 44, 206, 10, 104, 98, 172, 171, 59]

[38, 24, 35, 81, 189, 122, 103, 130, 193, 88, 167, 25, 8, 105, 161, 9, 46, 148, 74]

[49, 54, 65, 143, 186, 2, 57, 192, 178, 118, 190, 95, 11, 22, 129, 28, 91, 188, 141]

[61, 19, 78, 67, 69, 99, 162, 96, 131, 79, 63, 116, 163, 72, 6, 177, 20, 52, 36]

[71, 156, 80, 33, 202, 198, 15, 133, 170, 205, 85, 152, 165, 27, 83, 132, 200, 17, 60]

[89, 146, 4, 101, 113, 194, 119, 114, 40, 151, 207, 155, 140, 185, 108, 117, 102, 154, 123]

[94, 34, 84, 183, 90, 47, 121, 42, 124, 144, 77, 112, 149, 97, 136, 164, 127, 58, 43]

[125, 13, 182, 109, 197, 16, 184, 110, 187, 66, 106, 150, 21, 173, 157, 181, 204, 139, 145]

[168, 100, 76, 62, 142, 30, 41, 23, 147, 191, 50, 179, 120, 86, 195, 26, 1, 87, 18]

初次列调整(开始人工干预)

lie_index = [4, 5, 1, 8, 9, 2, 0, 10, 3, 6, 7]

第二次列调整

lie_index = [4, 5, 10, 3, 6, 1, 8, 9, 2, 0, 7 ]

对第四列第五列进行细节的调整

对于附件4:

3.1 数据加载与预处理

首先,加载数据文件t4.mat,并将其内容转换为double类型,以便进行后续的计算与处理。

load 't4.mat';
for i = 1:209t4{i,1} = double(t4{i,1}); %转化为double型
end
bm=t4;
3.2 误差矩阵计算

接下来,计算图像之间的误差矩阵W,其计算过程通过比较每对图像的像素差异来确定误差。每个图像的误差由180个像素值的差异组成,并根据给定的参数afa和beta进行权重调整。通过遍历所有图像对,最终得到误差矩阵W。

W=inf*ones(209,209); %W为误差矩阵
afa=1;beta=1;
for i=1:209for j=1:209W(i,j)=0;for k=1:180w=(bm{i,1}(k,72)-afa*bm{j,1}(k,1)-beta)^2/180;   W(i,j)=W(i,j)+w;endend
end
3.3 图像二值化处理

为了更好地比较图像,接下来对每一幅图像进行二值化处理。通过graythresh函数自动计算图像的最佳阈值,并使用im2bw函数将图像转换为二值图像。

for i=1:209level=graythresh(t4{i,1});bm{i,1}=im2bw(t4{i,1},level); 
end
3.4 行首图像的识别与人工干预

为了进行图像排序,首先需要识别每一行的“行首”图像。通过分析每个图像的像素总和来判断每一行的首图。对于某些特殊图像,如不符合常规规律的图像(例如编号为147的图像),通过人工干预进行修正。

k=0;
for i=1:209b=0;for j=1:9b=b+sum(bm{i,1}(:,j));endif(b==180*9)k=k+1;left(k)=i;     %每行第一个end
end
3.5 图像配准与排序

在完成图像的二值化和行首图像的识别后,通过误差矩阵W对图像进行排序。对于每一行,选择与当前图像误差最小的图像作为下一个图像,逐步完成排序。当出现多个候选匹配项时,系统会进行人工干预,用户选择最合适的匹配项。最终,通过人工干预,完成图像排序。

n=21;
for ci=1:18k=find(W(n,:)==min(W(n,:)));lo=length(k);if(lo>1)kfor i=1:los(:,[1:72])=bm{n,1};s(:,[73:144])=bm{k(i),1};imwrite(s,'lena.jpg','quality',100); figure;imshow('lena.jpg')endb=input('人工干预'); %当出现多个可与当前匹配项时进行人工干预,输入b为人认为较符合匹配的序号if(b==0)for i=1:loW(n,k)=inf;endclose all;elsek=k(b);endendk=k;W(n,k)=inf;be(ci)=k;n=k;close all;
end

对于附件5

4.1 数据加载与预处理

首先,加载数据文件hang1.mat、hang2.mat、tu.mat以及hang.txt,并将文件中的数据进行预处理。特别地,将tu中的数据转换为double型,以便进行后续计算。

load 'hang1.mat';
load 'hang2.mat';
load 'tu.mat';
hang=load('hang.txt');
for i = 1:418tu{i,1} = double(tu{i,1}); %转化为double型
end
bm=tu;
4.2 误差矩阵构建与最小路径选择

对于每一行图像数据,我们首先跳过第6行(由于该行存在大量错误)。然后,我们根据图像之间的差异构建误差矩阵W。误差矩阵的计算涉及到图像特征(如hang1、hang2)与图像之间的误差。计算过程考虑了图像的相对位置以及权重因子afa和beta,计算出每一对图像的误差值。误差矩阵的构建过程中考虑了不同情况下的像素值差异,确保误差最小化。

for r=1:11if(r==6)continue;   %第6行错误很多,应全部用人工干预endju=hang(r,:);n=length(ju);W=inf*ones(n,n);afa=1; beta=1;for i=1:nfor j=1:n W(i,j)=0;w3=(hang1(i)-hang1(j))^2/180;w4=(hang2(i)-hang2(j))^2/180;for k=1:180w1=(bm{ju(i),1}(k,72)-afa*bm{ju(j),1}(k,1)-beta)^2/180;   %误差矩阵% 不同情况下的误差计算if((mod(ju(i),2)==1)&(mod(ju(j),2)==1))w2=(bm{ju(j)+1,1}(k,72)-afa*bm{ju(i)+1+1,1}(k,1)-beta)^2/180;elseif((mod(ju(i),2)==1)&(mod(ju(j),2)==0))w2=(bm{ju(j)-1,1}(k,72)-afa*bm{ju(i)+1,1}(k,1)-beta)^2/180; elseif((mod(ju(i),2)==0)&(mod(ju(j),2)==1))w2=(bm{ju(j)+1,1}(k,72)-afa*bm{ju(i)-1,1}(k,1)-beta)^2/180; elseif((mod(ju(i),2)==0)&(mod(ju(j),2)==0))w2=(bm{ju(j)-1,1}(k,72)-afa*bm{ju(i)-1,1}(k,1)-beta)^2/180; endW(i,j)=W(i,j)+w1+w2+w3+w4;endendend
4.3 最小误差路径选择

通过对误差矩阵W的逐行分析,选择每行最小的误差路径,并依次确定每个图像的排序。对于每一行,我们选择误差最小的图像,并将其从误差矩阵中剔除,保证每次选择的图像是误差最小的。

n=1;
for ci=1:18k=find(W(n,:)==min(W(n,:)));if(k==n)W(n,k)=inf;k=find(W(n,:)==min(W(n,:)));endk=k(1);be(r,ci)=ju(k);W(n,k)=inf;n=k;for i=1:19W(i,n)=inf;end
end

附录1:

附录2:

附录3:

附录4:

附录5:xb = xa+208

158 224 251 281 311 301 368 350 221 133 217 38 59 380 164 330 41 95 274
179 22 73 154 357 89 52 385 250 45 242 289 159 29 119 122 295 305 11
374 307 170 86 61 77 243 197 190 124 276 91 277 114 264 376 174 402 288
400 24 323 340 390 348 414 313 69 364 398 175 266 187 146 351 195 80 67
178 215 300 361 76 383 132 232 334 4 304 342 83 142 280 5 326 408 181
229 370 360 234 415 117 317 395 310 58 25 36 206 130 417 285 115 49 27
293 344 63 403 101 382 186 40 34 356 108 405 44 261 327 388 148 319 71
332 391 257 315 337 93 135 128 152 335 236 18 138 377 255 81 366 245 345
8 16 172 298 155 9 139 65 150 254 353 371 2 162 55 272 283 410 211
48 267 97 104 191 322 239 68 144 105 125 260 238 203 32 411 166 291 20
199 87 194 219 247 13 209 269 227 54 100 183 214 202 112 2 24 2 110

反面的矩阵 = 正面的矩阵镜像翻转

相关文章:

  • 一个关于fsaverage bem文件的说明
  • 五一感想:知识产权加速劳动价值!
  • window 显示驱动开发-线程和同步级别一级(二)
  • SecureCrt设置显示区域横列数
  • PDF扫描件交叉合并工具
  • 从PotPlayer到专业播放器—基于 RTSP|RTMP播放器功能、架构、工程能力的全面对比分析
  • MySQL 8.4.5 源码编译安装指南
  • NLP 和大模型技术路线
  • Baichuan-Audio: 端到端语音交互统一框架
  • C#中读取文件夹(包含固定字样文件名)
  • 通过Kubernetes 外部 DNS控制器来自动管理Azure DNS 和 AKS
  • 算法中的数学:算术基本定理
  • QuecPython+腾讯云:快速连接腾讯云l0T平台
  • Hive优化秘籍:大数据处理加速之道
  • OpenGL超大分辨率图像显示
  • 恩智浦 GoPoint 全面解析:初学者的嵌入式 AI 学习指南
  • venv和pyenv在mac上
  • 【星海随笔】信息安全管理与法律法规
  • python3使用:macOS上通过Homebrew安装pip库
  • C++GO语言微服务项目之 go语言基础语法
  • 观察|印巴交火开始升级,是否会升级为第四次印巴战争?
  • 习近平《在庆祝中华全国总工会成立100周年暨全国劳动模范和先进工作者表彰大会上的讲话》单行本出版
  • 陈雯出任外交部离退休干部局局长,此前为外交部办公厅副主任
  • A股三大股指集体高开大涨超1%,券商、房地产涨幅居前
  • 经济日报:落实落细更加积极的财政政策
  • 五一假期上海楼市延续向好态势,成交量同比增加36%