一、摘要
本研究针对甲骨文图像处理展开研究,详细阐述了相关实验过程与成果。实验涵盖图像校正、噪声去除、多边形拟合、文字提取与分割等内容。在图像预处理阶段,通过灰度化、二值化、连通域分析等操作去除背景噪声,增强文字清晰度。利用霍夫变换检测直线并旋转图像实现校正,以质心为原点建系,再经腐蚀、膨胀优化图像。多边形拟合采用bwboundaries函数得到甲骨外轮廓。文字提取经多种方法尝试,确定先膨胀再提取文字,按连通域面积排序后重新排列。
二、实验思路分析
(一)第(1)、(2)问的处理
该任务的主要目标是实现对图像的处理,包括求取图像的质心、对图像进行整体校正,以及将图像中的文字调整为垂直和水平走向。在实际处理图像的过程当中,发现原始图像中甲骨外部的白色区域是无关紧要的部分,这些区域可以视为背景噪声,不仅对任务无帮助,还可能干扰文字的识别和校正效果。因此,我设想在去除背景噪声的同时,尝试提升甲骨文上文字的清晰度,以便更准确地识别文字的走向信息。在去噪和增强文字后,我计划利用Hough变换对图像中的文字走向进行检测,提取其方向信息,并依据这一信息对图像进行校正,确保文字走向变为标准的垂直和水平。这一处理流程将帮助顺利完成实验中的(1)、(2)两个问题,为后续研究奠定基础。
(二)第(3)问的处理
该任务的核心目标是对甲骨外部轮廓进行精确拟合,以便为后续的研究与分析提供可靠的形状信息。为实现这一目标,首先需要通过边缘检测算法对图像进行处理,提取甲骨的边缘轮廓。边缘检测是一种常用的方法,可以有效地找到图像中显著的边界信息。在获取到甲骨的边缘后,可以进一步利用多边形拟合的相关算法对这些边缘进行拟合处理,生成更加规则且简洁的轮廓表示。但是为了确保轮廓提取的准确性,在此之前需要结合(1)、(2)两问中涉及的图像预处理工作,例如去除背景噪声、提升图像清晰度以及对图像方向的校正等。这些前置处理能够显著改善边缘检测和拟合的效果,避免背景干扰或不准确的边缘检测导致的误差。基于此步骤,能够顺利解决实验中的第(3)问,为甲骨形状的进一步研究提供清晰且精确的轮廓数据。
(三)第(4)问的处理
该任务的主要目标是从图像中提取出甲骨文字符,并根据字符在图中的位置进行排列。这一过程需要在图像预处理的基础上进行进一步处理。在预处理阶段,我设想将甲骨内部的白色区域视为文字符号的轨迹,通过这一假设可以初步解决字符提取的问题。然而,在实际操作中发现甲骨内部存在裂缝、字符粘连等情况,这些问题会对提取效果产生干扰,导致提取结果不准确。因此,如果能够手动圈选出认为是干扰的区域并加以处理,将会显著提升字符提取的精度。为此了解到,RIO方法可以用于对特定区域进行定向处理。通过利用RIO对干扰区域进行标注和排除,干扰问题就能够得到有效解决。在完成干扰区域的处理后,就可以对图像中的字符进行提取。这一过程需要识别所有的连通区域,并确保能够清晰区分各连通区域之间的边界。由于题目要求是有序排列,可知任务要求提取出的文字需要按照一定的顺序进行排列,考虑可以通过对文字连通域的面积大小进行排序从而实现对文字的排序。进一步查阅资料后,我发现MATLAB中自带的bwlabel和regionprops函数可以很好地实现这一功能。其中,bwlabel用于标记连通区域,而regionprops则能提取每个连通区域的属性信息,如位置、形状等。通过这些工具,可以进一步有效地提取出图像中的甲骨文字符,并根据其原始位置进行合理排列,从而完成任务目标,这也是未来工作的一部分。
三、实验流程设计
(一)第1、2问的流程设计
这一部分任务的目标是对原始图像进行处理和校正,使图像中的甲骨文文字排列规范化,为后续的分析和识别提供支持。整个流程从原始图像的输入开始。首先,进行图像的预处理:将原始图像转化为灰度图像,减少颜色信息的干扰并突出主要特征;然后通过二值化操作简化为黑白二值图像,使图像中的甲骨文与背景得以清晰区分。为了进一步消除噪声,通过膨胀和腐蚀操作去除二值图中的细小噪声。接下来,通过连通域分析识别图像中彼此连通的区域,并对其进行编号处理,同时剔除噪声区域,仅保留与甲骨文相关的有效区域。这些连通域的主要部分会被提取出来,并进行质心计算,计算出的质心将被用作坐标原点,为后续的校正提供参考。在此基础上,使用Canny边缘检测方法提取图像中甲骨文字的边缘,通过霍夫变换检测出图像中的直线,并标注出最长的直线。通过最长线段的方向与默认的X轴之间的夹角,判断图像的整体倾斜角度,并进行旋转校正,从而使文字的方向与垂直或水平标准保持一致。这一流程通过图像预处理、连通域分析、噪声剔除、质心计算、直线检测与校正等步骤,逐步优化了甲骨文图像的排版方向。最终,系统完成对甲骨文的分割和标准化处理,确保输出的甲骨文图像具备良好的规范性和分析价值。
(二)第3问的流程设计
这个任务必不可少的肯定是将图像转化为灰度图,在对其进行二值化处理,然后利用膨胀和腐蚀清楚边缘处的小噪声,使得后续的边缘检测更加的准确。然后同样的利用连通区域分析,图片中有两个较大的连通区域,一个是图像的背景,一个是甲骨,背景的连通区域肯定比甲骨大,所以肯定选择连通区域面积第二大的作为甲骨区域。然后同样利用Canny边缘检测甲骨的边缘。获得其边缘后,使用bwboundaries函数来对其进行多边形拟合。
若是详细分析这个任务的具体内容,我的目标是利用多边形拟合算法提取甲骨的外轮廓,为此,我设计并执行了完整的图像处理流程。从一开始,我将甲骨的原始图像导入到系统中,这为整个过程提供了原始数据。随后,我对图像进行了预处理,首先将其灰度化,将原本复杂的彩色图像简化为单一的灰度值,这一步显著减少了不必要的信息干扰,同时保留了甲骨的形态特征。接着,我对灰度图像进行了二值化处理,将图像转化为黑白像素,从而更清晰地将甲骨与背景区分开来。这一步为后续的轮廓提取奠定了基础。
在完成图像预处理后,我开始着手对图像进行连通域分析。这一步是为了识别出图像中与甲骨相关的连通区域,同时剔除噪声和无关区域。通过连通域判断,我将目标区域提取出来,并对较小的无效区域进行了颜色反转,确保只保留甲骨的主要部分作为后续处理的对象。接下来,我对甲骨区域进行了图像形态学处理,包括膨胀和腐蚀等操作。这些处理步骤让我能够修复图像中的小缺陷,平滑甲骨边界,同时加强甲骨区域的完整性,为边缘检测做准备。在获取了形态处理后的图像后,我使用了Canny边缘检测算法。这一步让我能够准确提取甲骨的外轮廓,Canny算法的强大性能确保了边缘检测的精确性,即使甲骨表面可能存在一定的噪声或模糊区域,也可以得到清晰的边缘信息。通过边缘检测,我成功获得了甲骨的轮廓线,为外形拟合提供了必要的数据支撑。最后,在轮廓检测完成后,我使用多边形拟合算法bwboundaries对甲骨的外轮廓进行了拟合。我通过拟合方法将甲骨复杂的外形抽象成规则的多边形,从而更直观地表示甲骨的外部特征。在拟合过程中,我反复调整拟合参数,确保拟合的多边形既能贴合甲骨的实际形状,又不过度复杂化。我还对拟合结果进行了验证,确保拟合的多边形能够完整地覆盖甲骨的外轮廓,同时避免过拟合现象。
(三)第4问的流程设计
首先,我从原始甲骨文图像的导入开始,这是整个处理流程的基础。我将原始图像输入系统后,立即进入图像预处理阶段。在这一阶段,我通过灰度化操作将原始彩色图像转化为灰度图像,这一过程有效地减少了多余的颜色信息,同时突出甲骨文的主要特征,使文字的结构更加清晰可见。接着,我对灰度图像进行了二值化处理,将图像中的像素值转化为仅包含黑白两色的二值图,从而能够更好地分离甲骨文与背景。这一步的目的是明确区分目标区域(甲骨文文字)和无关区域(背景或噪声)。完成图像预处理后,我进入了连通域分析阶段。这一步至关重要,我通过连通域判断技术对图像中的连通区域进行分析,提取出甲骨文所在的主要连通区域,并对这些区域进行编号。与此同时,我剔除了小的噪声区域以及不相关的连通域,确保只保留真正与甲骨文文字相关的部分。通过这一操作,我有效地筛选出图像中与文字相关的核心区域,为后续的处理提供了可靠的数据基础。
在获得文字的主要连通域后,我开始处理文字的连通域区域。首先,我通过区域划分技术,将连通域中包含的多个字符进行分割,确保每个字符能够单独提取出来。这一步需要对每个区域的几何特性进行分析,例如面积、宽高比等,确保文字的分割是准确的。此外,我还利用区域间的距离等几何特性,进一步优化字符分割的效果。这一步的重点是将原本连在一起的文字块分割为独立的字符,同时保证每个字符的完整性和清晰度。在完成文字的分割后,我对分割得到的字符进行排序。为此,我设计了一套基于字符几何位置的有序规则。例如,根据甲骨文的书写规律,从上到下、从左到右的顺序,对所有分割后的字符进行重新排列,确保输出的符号是有序的。这一步不仅需要考虑字符的位置关系,还要结合甲骨文的实际书写习惯进行调整,确保最终输出的符号符合逻辑和规范。
这套有序的排列需要考虑怎么有序,可以是考虑连通域的面积大小,按照连通域面积大小进行排序;也可以按照位置从左到右从上到下进行排序,若是按照位置顺序进行排序,则有两种方式可以选择,可以选择质心排序法或者直线排序法,本文选用的是按照连通域面积大小进行有序排列方法。
(四)补充工作
补充工作部分可以自行寻找更加清晰的甲骨文图片,本任务所提供的甲骨文图片清晰度较差,导致最终得到的效果并不理想,然而方法是简单且高效的,后续实验结果表明,更换清晰度更好的甲骨文图片后文字分割的效果有了极大的改善。本部分考虑的思路与上述步骤相同,需要注意的是由于图片的形态及明暗部分并不相同,需要考虑使用自适应阈值法方可对图像进行更好的二值化处理。
整个实验流程的拓扑图如下所示。
四、第1、2问实验代码分析
(一)二值图像转换
% 读取原始图像
img = imread('Jiagu.png'); % 这里 'Jiagu.png' 替换为你的图片文件名
% 将图像转换为灰度图像
gray_img = rgb2gray(img);
% 显示灰度图像
figure;
imshow(gray_img);
title('灰度图像');
% 对灰度图像进行二值化处理
% 使用Otsu的二值化方法来自动计算阈值
threshold_level = graythresh(gray_img); % 自动计算阈值
binary_img = imbinarize(gray_img, threshold_level); % 根据计算的阈值进行二值化
% 显示二值化图像
figure;
imshow(binary_img);
title('二值化图像');
% 将二值图像保存为 'erzhi.png'
imwrite(binary_img, 'erzhi.png'); % 保存二值图像为 'erzhi.png'
disp('二值化图像已保存为 erzhi.png');
(二)区域颜色变换
% 对二值化后的人工处理过的图像进行黑色区域去除
% 读取二值图像
img = imread('newer.png'); % 读取图像文件,假设它已经是二值化图像
% 如果图像是彩色的,转换为灰度图并二值化
if size(img, 3) == 3
img = rgb2gray(img); % 如果图像是彩色图像,转换为灰度图
img = imbinarize(img); % 将灰度图像转换为二值图像
end
% 提取反转后的二值图像
BW_inverted = max(img(:)) - img; % 反转二值图像,白变黑,黑变白
% 对反转后的图像进行连通区域标记
[labeled_img, num] = bwlabel(BW_inverted); % 连通区域标记
area_stats = regionprops(labeled_img, 'Area'); % 获取区域的大小(像素数)
% 对区域按大小进行排序,找到第二到第五大连通区域
[sorted_areas, sort_indexes] = sort([area_stats.Area], 'descend');
second_largest_blob_index = sort_indexes(2); % 第二大连通区域的索引
third_largest_blob_index = sort_indexes(3); % 第三大连通区域的索引
fourth_largest_blob_index = sort_indexes(4); % 第四大连通区域的索引
fifth_largest_blob_index = sort_indexes(5); % 第五大连通区域的索引
% 创建一个二值图像,标记第二到第五大连通区域
second_largest_blob_img = ismember(labeled_img, second_largest_blob_index);
third_largest_blob_img = ismember(labeled_img, third_largest_blob_index);
fourth_largest_blob_img = ismember(labeled_img, fourth_largest_blob_index);
fifth_largest_blob_img = ismember(labeled_img, fifth_largest_blob_index);
% 反转第二到第五大连通区域的颜色
outputImg = img; % 复制原始图像
outputImg(second_largest_blob_img) = ~outputImg(second_largest_blob_img); % 反转第二大连通区域的颜色
outputImg(third_largest_blob_img) = ~outputImg(third_largest_blob_img); % 反转第三大连通区域的颜色
outputImg(fourth_largest_blob_img) = ~outputImg(fourth_largest_blob_img); % 反转第四大连通区域的颜色
outputImg(fifth_largest_blob_img) = ~outputImg(fifth_largest_blob_img); % 反转第五大连通区域的颜色
% 显示结果
figure;
imshow(outputImg);
title('颜色反转后的第二到第五大连通区域');
imwrite(outputImg, 'newer0.png');
上述代码中最关键的是对连通域面积第二至五大的区域进行颜色反转,至于为什么是二至五大的区域,通过观察图像或阅读后续分析即可理解。
(三)人工对图像进行处理(若需要可用,本任务需要此代码)
% 读取二值图像
I = imread('erzhi.png'); % 这里替换为二值图像文件路径
% 如果图像是彩色图像,转换为灰度图并二值化
if size(I, 3) == 3
I = rgb2gray(I);
I = imbinarize(I); % 转换为二值图像
end
% 显示原始图像
figure;
imshow(I);
title('选择要修改的区域');
% 使用 roipoly 函数让用户选择一个多边形区域
BW = roipoly(I); % 返回一个与原图像大小相同的逻辑图像,表示选中的区域
% 将选中的区域设置为白色
I(BW) = 1; % 将选中区域的像素值设为1(白色)
% 显示处理后的图像
figure;
imshow(I);
title('处理后的图像');
% 将修改后的图像保存为新的文件
imwrite(I, 'newer.png'); % 保存为 modified_image.png(你可以选择其他文件名和格式)
(四)霍夫变换检测直线,并求质心
%终极代码,添加坐标系
close all;
clear;
clc;
% 读入图像并进行边缘检测
a = imread('newer1.png');
figure;
a = a(:,:,1); % 只取图像的第一个通道(假设图像是灰度图)
subplot(221);
imshow(a);
% 使用拉普拉斯算法进行边缘检测
bw1 = LapuLas(a);
subplot(222);
imshow(bw1);
% 使用Hough变换提取直线
subplot(223);
[H, theta, rho] = naiveHough(bw1); % 调用自己编写的Hough函数
imshow(H, [], 'XData', theta, 'YData', rho, 'InitialMagnification', 'fit'); % 绘制Hough空间
xlabel('\theta (degrees)');
ylabel('\rho');
axis on, axis square, hold on;
% 提取Hough空间中的峰值点
P = houghpeaks(H, 6); % 提取6个峰值点
x = theta(P(:,2));
y = rho(P(:,1));
plot(x, y, 's', 'color', 'red'); % 标出极值点
title('Hough空间');
% 提取线段
lines = houghlines(bw1, theta, rho, P);
subplot(224)
imshow(a), hold on; % 显示原图并画出直线段
% 初始化变量以保存最长的线段
max_len = 0;
longest_line = [];
% 遍历所有检测到的直线段
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2]; % 线段的端点
len = norm(lines(k).point1 - lines(k).point2); % 计算直线段的长度
if len > max_len % 如果当前线段比之前找到的最长线段还长
max_len = len;
longest_line = xy; % 更新最长线段
end
end
% 绘制最长的直线段
if ~isempty(longest_line)
plot(longest_line(:, 1), longest_line(:, 2), 'LineWidth', 2, 'Color', 'blue'); % 画出最长直线段
plot(longest_line(1, 1), longest_line(1, 2), 'o', 'LineWidth', 2, 'Color', 'yellow'); % 起点
plot(longest_line(2, 1), longest_line(2, 2), 'o', 'LineWidth', 2, 'Color', 'red'); % 终点
% 计算直线与X轴的夹角
x1 = longest_line(1, 1);
y1 = longest_line(1, 2);
x2 = longest_line(2, 1);
y2 = longest_line(2, 2);
% 计算直线的斜率
dx = x2 - x1;
dy = y2 - y1;
% 使用atan2计算夹角
angle_radians = atan2(dy, dx); % 计算弧度
angle_degrees = rad2deg(angle_radians); % 转换为角度
% 确保角度在0到180度之间
if angle_degrees < 0
angle_degrees = angle_degrees + 180;
end
% 打印夹角
disp(['最长直线与X轴的夹角为: ', num2str(angle_degrees), '°']);
% 计算旋转角度,使最长直线与Y轴重合
rotation_angle = angle_degrees - 90; % 需要旋转的角度使直线与Y轴平行
% 顺时针旋转图像
rotated_image = imrotate(a, rotation_angle, 'bilinear', 'crop');
% 显示旋转后的图像
figure;
imshow(rotated_image);
title(['旋转后的图像, 旋转角度: ', num2str(rotation_angle), '°']);
% 保存旋转后的图像
imwrite(rotated_image, 'rotated_image.png');
disp('旋转后的图像已保存为 rotated_image.png');
% 设定原点 (243.0819, 317.5220)
origin_x = 243.0819;
origin_y = 317.5220;
% 旋转后的点
% 计算旋转后的坐标变换
theta_rad = deg2rad(rotation_angle); % 将角度转换为弧度
x_prime = origin_x * cos(theta_rad) + origin_y * sin(theta_rad);
y_prime = -origin_x * sin(theta_rad) + origin_y * cos(theta_rad);
% 在旋转后的图像上标记出新坐标系原点
hold on;
plot(x_prime, y_prime, 'go', 'MarkerSize', 10, 'LineWidth', 2); % 使用绿色圆圈标记原点
% 旋转后的直线 (Y轴) 和 90度旋转后的直线 (X轴)
% 绘制原点和坐标轴
% 标记新坐标系
axis equal;
line([x_prime-50, x_prime+50], [y_prime, y_prime], 'Color', 'red', 'LineWidth', 2); % X轴
line([x_prime, x_prime], [y_prime-50, y_prime+50], 'Color', 'blue', 'LineWidth', 2); % Y轴
text(x_prime + 10, y_prime, 'Origin', 'Color', 'green', 'FontSize', 12);
end
% Hough变换函数
function [ Hough, theta_range, rho_range ] = naiveHough(I)
[rows, cols] = size(I);
theta_maximum = 90;
rho_maximum = floor(sqrt(rows^2 + cols^2)) - 1;
theta_range = -theta_maximum:theta_maximum - 1;
rho_range = -rho_maximum:rho_maximum;
Hough = zeros(length(rho_range), length(theta_range));
for row = 1:rows
for col = 1:cols
if I(row, col) > 0 % 只检测边缘像素
x = col - 1;
y = row - 1;
for theta = theta_range
rho = round((x * cosd(theta)) + (y * sind(theta)));
rho_index = rho + rho_maximum + 1;
theta_index = theta + theta_maximum + 1;
Hough(rho_index, theta_index) = Hough(rho_index, theta_index) + 1;
end
end
end
end
end
% 拉普拉斯边缘提取函数
function [p] = LapuLas(e)
r = e;
[m, n] = size(e);
dd = sum(sum(e) / (m * n)); % 计算阈值
for x = 1:m
for y = 1:n
if (r(x, y) >= dd)
r(x, y) = 255;
else
r(x, y) = 0;
end
end
end
p = zeros(m - 1, n - 1);
for ii = 2:m - 1
for jj = 2:n - 1
p(ii, jj) = r(ii, jj + 1) + r(ii, jj - 1) + r(ii + 1, jj) + r(ii - 1, jj) - 4 * (r(ii, jj));
end
end
p = uint8(p);
end
观察图像可知,在甲骨文图像区域内使用霍夫变换检测出的最长直线(文字竖直排列方向)与默认X轴的夹角度数即为甲骨文图像旋转的角度。
(五)求质心
% 用于求质心的代码,求出质心坐标
% 读取二值图像
img = imread('newer0.png'); % 读取图像文件,假设它已经是二值化图像
% 如果图像是彩色图像,转换为灰度图并二值化
if size(img, 3) == 3
img = rgb2gray(img); % 如果图像是彩色图像,转换为灰度图
img = imbinarize(img); % 将灰度图像转换为二值图像
end
% 反转二值图像,白变黑,黑变白
BW_inverted = max(img(:)) - img;
% 膨胀图像
se = strel('square', 3); % 创建一个 3x3 的方形结构元素
dilated_img = imdilate(BW_inverted, se); % 对反转后的图像进行膨胀操作
% 对膨胀后的图像进行连通区域标记
[labeled_img, num] = bwlabel(dilated_img); % 连通区域标记
% 获取每个区域的面积信息
area_stats = regionprops(labeled_img, 'Area');
% 按照面积对区域进行排序,找到最大区域或指定区域的索引
[sorted_areas, sort_indexes] = sort([area_stats.Area], 'descend');
largest_blob_index = sort_indexes(1); % 最大连通区域的索引
second_largest_blob_index = sort_indexes(2); % 第二大连通区域的索引
% 获取最大区域的质心
largest_blob_img = ismember(labeled_img, largest_blob_index);
centroid_stats = regionprops(largest_blob_img, 'Centroid');
centroid = centroid_stats.Centroid; % 最大区域的质心
% 获取第二大区域的质心
second_largest_blob_img = ismember(labeled_img, second_largest_blob_index);
centroid_stats_2 = regionprops(second_largest_blob_img, 'Centroid');
centroid_2 = centroid_stats_2.Centroid; % 第二大区域的质心
% 输出质心坐标
disp('最大连通区域质心:');
disp(centroid);
% 可视化图像和质心
figure;
imshow(dilated_img); % 显示膨胀后的图像
hold on;
plot(centroid(1), centroid(2), 'r*', 'MarkerSize', 10); % 绘制最大连通区域的质心
title('膨胀图像的质心位置');
hold off;
本段代码可以输出最长直线与X轴的夹角以及质心的坐标。
(六)旋转图像
% 倒数第二步,对旋转后去除多余部分的图像添加坐标系
% 读取二值图像
img = imread('newer1.png'); % 读取图像文件,假设它已经是二值化图像
% 如果图像是彩色图像,转换为灰度图并二值化
if size(img, 3) == 3
img = rgb2gray(img); % 如果图像是彩色图像,转换为灰度图
img = imbinarize(img); % 将灰度图像转换为二值图像
end
% 反转二值图像,白变黑,黑变白
BW_inverted = max(img(:)) - img;
% 膨胀图像
se = strel('square', 3); % 创建一个 3x3 的方形结构元素
dilated_img = imdilate(BW_inverted, se); % 对反转后的图像进行膨胀操作
% 对膨胀后的图像进行连通区域标记
[labeled_img, num] = bwlabel(dilated_img); % 连通区域标记
% 获取每个区域的面积信息
area_stats = regionprops(labeled_img, 'Area');
% 按照面积对区域进行排序,找到最大区域或指定区域的索引
[sorted_areas, sort_indexes] = sort([area_stats.Area], 'descend');
largest_blob_index = sort_indexes(1); % 最大连通区域的索引
second_largest_blob_index = sort_indexes(2); % 第二大连通区域的索引
% 获取最大区域的质心
largest_blob_img = ismember(labeled_img, largest_blob_index);
centroid_stats = regionprops(largest_blob_img, 'Centroid');
centroid = centroid_stats.Centroid; % 最大区域的质心
% 获取第二大区域的质心
second_largest_blob_img = ismember(labeled_img, second_largest_blob_index);
centroid_stats_2 = regionprops(second_largest_blob_img, 'Centroid');
centroid_2 = centroid_stats_2.Centroid; % 第二大区域的质心
% 输出质心坐标
disp('最大连通区域质心:');
disp(centroid);
% 可视化图像和质心
figure;
imshow(dilated_img); % 显示膨胀后的图像
hold on;
plot(centroid(1), centroid(2), 'r*', 'MarkerSize', 10); % 绘制最大连通区域的质心
title('膨胀图像的质心位置');
hold off;
这里的代码可以参考旋转的方式,需要注意的是如果先旋转再提取文字效果会变差,旋转后的图像质量会进一步下降,需要自己适时权衡旋转图像与提取文字的先后顺序,本任务后续选择先提取文字再旋转图像。
(七)图像腐蚀操作(若需要)
% 单纯的腐蚀,极致的享受
% 读取原始图像
img = imread('Jiagu.png'); % 这里 'Jiagu.png' 替换为你的图片文件名
% 将图像转换为灰度图像
gray_img = rgb2gray(img);
% 显示灰度图像
figure;
imshow(gray_img);
title('灰度图像');
% 对灰度图像进行二值化处理
% 使用Otsu的二值化方法来自动计算阈值
threshold_level = graythresh(gray_img); % 自动计算阈值
binary_img = imbinarize(gray_img, threshold_level); % 根据计算的阈值进行二值化
% 显示二值化图像
figure;
imshow(binary_img);
title('二值化图像');
% 定义结构元素(根据图像特点调整大小)
se = strel('disk', 1); % 'disk' 形态学结构元素,半径为 1(可以根据需要调整)
% 腐蚀操作:去除小的白色噪点
eroded_img = imerode(binary_img, se);
% 显示腐蚀后的图像
figure;
imshow(eroded_img);
title('腐蚀后的图像');
% 膨胀操作:增强目标区域,填补小空洞
dilated_img = imdilate(eroded_img, se);
dilated_img_2 = imdilate(dilated_img, se); % 两次膨胀
dilated_img_3 = imdilate(dilated_img_2, se); % 三次膨胀
dilated_img_4 = imdilate(dilated_img_3, se); % 四次膨胀
dilated_img_5 = imdilate(dilated_img_4, se); % 五次膨胀
dilated_img_6 = imdilate(dilated_img_5, se); % 五次膨胀
dilated_img_7 = imdilate(dilated_img_6, se); % 五次膨胀
dilated_img_8 = imdilate(dilated_img_7, se); % 五次膨胀
dilated_img_9 = imdilate(dilated_img_8, se); % 五次膨胀
% 显示膨胀后的图像
figure;
imshow(dilated_img);
title('膨胀后的图像');
% 显示三次膨胀后的图像
figure;
imshow(dilated_img_3);
title('三次膨胀后的图像');
% 显示五次膨胀后的图像
figure;
imshow(dilated_img_5);
title('五次膨胀后的图像');
% 显示七次膨胀后的图像
figure;
imshow(dilated_img_7);
title('七次膨胀后的图像');
% 显示九次膨胀后的图像
figure;
imshow(dilated_img_9);
title('九次膨胀后的图像');
% 反转二值图像
BW_inverted = max(binary_img(:)) - binary_img; % 反转图像:黑白互换
% 显示反转后的二值图像
figure;
imshow(BW_inverted);
title('反转后的二值图像');
图像的腐蚀次数可以自行根据腐蚀后的效果增加或减少。
五、第1、2问实验结果分析
(一)图像校正&噪声去除
原始甲骨文图像如下图所示,以其作为目标图像进行进一步处理,原图像实际质量很一般且不同于原图,在甲骨文图像的左上角发现白色区域并没有完全包含黑色甲骨文图像,故需要上述代码中的人工处理图像,人为创造出黑白分界使得白色背景完全包含黑色甲骨文图像,方可继续进行后续任务。
原始图像先灰度化处理之后再进行二值化处理,处理后的二值化图像如下图2所示,二值图像也会作为今后实验的重要一步。
如下图所示,红色矩形中的对角线处黑白分界为人为创造,实际中并不过多影响最终效果,故可采用,方便后续的工作进一步开展。
使用连通域提取去除法,将得到的二值图像连通域面积第二、三、四、五大的部分进行去除得到去除背景后的二值图像,得到的图像如下图所示。
对去除背景后的二值图像使用霍夫变换检测最长直线,在此过程中调整参数使得提取Hough空间中的6个峰值点得到最长的直线,以此作为甲骨文图片的正向校正处,通过霍夫变换得到的结果如下图所示。
检测得到的最长直线的图像如下图所示。
以霍夫变换检测出的最长直线作为旋转后的Y轴,计算与图像默认X轴之间的夹角得到结果为29.1315°,并使其旋转相应度数得到如下图所示旋转后的图像。
将旋转后的图像同样进行连通域检测,去除连通域面积第2、3、4、5大的部分得到如下图图像校正后去除背景的图像。
对去除背景的图像进行颜色反转,并对甲骨文主体内容进行腐蚀运算,得到如下图所示的保留外轮廓的二值图像,这也是噪声去除后得到的甲骨文外轮廓二值图像。
对保留外轮廓的二值图像进行质心检测,并标记出质心的位置,所得结果如下图质心检测结果所示,其坐标为243.0819,317.5220。
对去除背景后的二值图像进行去除噪声运算,最终得到如下图所示保留文字的二值图像,在去除噪声的同时也对其进行线性结构膨胀运算,使得文字更加清晰。
对去除背景后的二值图像进行建系操作,使得质心为原点,默认X轴为甲骨文图像的X轴,霍夫变换检测到的直线为Y轴,建系结果如下图所示。