一、分析
2.1该任务是实现求出图像的质心,并且对图像进行校正,还有实现对图像中的文字调整为走向垂直和水平。由于原始图像中的甲骨外部的白色区域是我所不想要的,即为原始图像中的噪声和背景。所以我就在想在去除背景噪声的同时也可以对甲骨文上的文字的清晰度进行提高的方法,在该基础上使用Hough变换检测图像文字的走向,并根据其走向信息来校正图像的方向。借此完成实验的(1)、(2)问。
2.2该任务是实现对甲骨外部轮廓进行拟合,要找到轮廓可以利用边缘检测算法来找到甲骨的边缘,而对找到的边缘可以利用多边形拟合的相关算法进行解决。
而在进行这些之前,同样要在2.1问图像预处理的部分基础上进行解决,从而解决第(3)问。
2.3该任务是要从图像中提取出来文字符,并且按照图中的位置进行排列。我在想在图像预处理的基础上,如果都将甲骨内部的白色区域都当作文字符号的轨迹,那就可以解决了,但是其真实的内部有裂缝、并且操作字符粘连的情况,如果能够手动的将自认为是干扰的区域圈出来处理就好了,通过网上查阅资料,发现RIO可以对确定的区域进行定向出来,所以通过RIO将干扰区域圈出来处理,然后就可以对字符进行提取了,提取方式是可以找到该所有的连通区域,并且能够很好的区分各个连通区域之间的边界。通过查阅资料,我发现matlab中自带有bwlabel和regionprops函数可以实现这些功能。
二、具体分析+流程图
3.1将原始图像转化为灰度图像,并进行二值化处理,得到二值图后,然后利用膨胀和腐蚀去除二值图中的细小噪声,然后利用得到的图像通过连通域分析找到图像中的主要对象,然后对该对象进行质心计算,并将计算得到的质心作为坐标原点。由于二值图中要识别文字,所以可以利用Canny的边缘检测的方法来识别文字的边缘,然后对其使用Hough变换检测图像中的直线,通过这条直线反映文字的走向。由于要对图像进行校正,由于各个文字的都有属于自己的文字走向,所以要使得图片尽量的被校正,所以这里我选择使用检测的最长线段的走向来决定整个图像的倾斜方向,然后计算该线段与垂直的角度,来达到使得文字垂直或水平排列。
3.2必不可少的肯定是将图像转化为灰度图,在对其进行二值化处理,然后利用膨胀和腐蚀清楚边缘处的小噪声,使得后续的边缘检测更加的准确。然后同样的利用连通区域分析,图片中有两个较大的连通区域,一个是图像的背景,一个是甲骨,背景的连通区域肯定比甲骨大,所以肯定选择连通区域面积第二大的作为甲骨区域。然后同样利用Canny边缘检测甲骨的边缘。获得其边缘后,使用boundary函数来对其进行多边形拟合。
3.3首先,肯定是转化为灰度图、然后利用自适应阈值方法进行二值化,使得文字更加的凸显。然后利用膨胀和腐蚀去除细小噪声。然后利用RIO对特定区域的干扰噪声(裂痕、粘连字符)进行处理,然后利用bwlabel和regionprops的方法对字符进行提取。最后更加字符的水平和垂直位置对字符进行排列。
三、结果展示
3.1结果
①二值化和质心计算结果
②二值图
③霍夫空间映射
④图像纠偏结果
结果分析:通过在边缘检测之前对图像进行开运算(膨胀和腐蚀操作),使得开运算得到的图像比原始图像更加清晰和平滑。有效的去除了原始图像中零散的小噪声,使得甲骨外轮廓更加的平滑。通过连通图方法使得甲骨中的文字信息轮廓得到了保留,为后续的文字提取提供了便利,膨胀和腐蚀的操作在一定程度上使得部分文字信息被去除,使得文字的形状被改变。同时在利用Hough变换找走向的时候,当出现多个不同方向的文字,导致Hough无法准确找到主要的方向。在对质心进行计算的时候,由于是根据较大的连通区域来计算的,会存在受到其他对象的影响,导致计算的质心位置坐标有误差。
3.2结果
甲骨轮廓的多边形拟合结果前后展示
结果分析:该大体上拟合了甲骨外部的轮廓,但是有些区域没有实现精确的拟合效果(见下图),这些缺点是由于boundary函数本身的缺陷,其函数对弯曲、复杂曲线的拟合效果不好,只能进行生成直线段和简单曲线段的拟合,除此之外,因为不能对内部空洞的进行外部拟合。
3.3结果
字符提取排列结果
字符提取排列结果
结果分析:从以上的字符提取结果上看,提取的字符比较清晰,但是也存在与我们认知矛盾的地方(如下图),有的我们认为是一个字的,其分成了两个字。这样的矛盾且复杂的地方,可能需要使用一些更加先进的分割技术来提高其分隔的准确性。
四、实验代码
3.1实验代码:
% 转换图像为灰度 gray_img = rgb2gray(img); % 二值化图像 bw_img = imbinarize(gray_img); % 形态学操作去除噪声 se = strel('diamond', 2); dilated_img = imdilate(bw_img, se); se = strel('diamond',2); bw_img = imerode(dilated_img, se); im = bwareaopen(bw_img,100); % 提取连通区域及计算质心 BW_inverted = max(bw_img(:)) - bw_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(1); largest_blob_img = ismember(labeled_img, second_largest_blob_index); centroid_stats = regionprops(largest_blob_img, 'Centroid'); centroid = centroid_stats.Centroid; % 霍夫变换检测直线 img_edge = edge(BW_inverted, 'canny'); [H, theta, rho] = hough(img_edge); P = houghpeaks(H, 30, 'threshold', ceil(0.3 * max(H(:)))); lines = houghlines(BW_inverted, theta, rho, P, 'FillGap', 10, 'Minlength', 2); % 计算最长线段角度并旋转图像 max_len = 0; 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; xy_long = xy; end end dx = xy_long(2,1) - xy_long(1,1); dy = xy_long(2,2) - xy_long(1,2); angle_radians = atan2(dy, dx); angle_degrees = rad2deg(angle_radians) - 90; rotated_image = imrotate(img, -angle_degrees, 'bilinear', 'crop');
3.2实验代码:
% 二值化图像 gray_img = rgb2gray(rotated_image); bw_img = imbinarize(gray_img); % 形态学操作清理图像 se = strel('diamond', 1); dilated_img = imdilate(bw_img, se); se = strel('diamond', 8); bw_img = imerode(dilated_img, se); BW_inverted = max(bw_img(:)) - bw_img; im = bwareaopen(BW_inverted, 5000); % 提取特定区域并进行多边形拟合 [labeled_img, num] = bwlabel(im); area_stats = regionprops(labeled_img, 'Area'); [sorted_areas, sort_indexes] = sort([area_stats.Area], 'descend'); second_largest_blob_index = sort_indexes(2); largest_blob_img = ismember(labeled_img, second_largest_blob_index); edges = edge(largest_blob_img, 'canny'); [edgeY, edgeX] = find(edges); [B,~] = boundary(edgeX, edgeY);
3.3实验代码:
% 转换图像为灰度 gray_img = rgb2gray(img); % 使用自适应阈值方法计算局部阈值 T = adaptthresh(gray_img, 0.0001, 'ForegroundPolarity','bright','Statistic','mean','NeighborhoodSize', 11); % 应用自适应阈值进行二值化 bwImg = imbinarize(gray_img, T); im = bwareaopen(bwImg,30); % 形态学操作清理图像 se = strel('diamond', 2); dilated_img = imdilate(im, se); im = bwareaopen(dilated_img,200); se = strel('diamond',1); im = imerode(im, se); % 定义并处理特定ROI以去除噪声和粘连字符 roi = [416, 610, 10, 10]; % 示例ROI roiImg = im(roi(2):(roi(2)+roi(4)-1), roi(1):(roi(1)+roi(3)-1)); se = strel('line', 5, 0); erodedRoiImg = imerode(roiImg, se); im(roi(2):(roi(2)+roi(4)-1), roi(1):(roi(1)+roi(3)-1)) = erodedRoiImg; % 转换为逻辑数组并应用bwlabel找到所有连通域 if ~islogical(im) im = imbinarize(im); end [labels, num] = bwlabel(im); stats = regionprops(labels, 'BoundingBox', 'Image'); % 初始化字符数组并提取每个连通域 characters = cell(num, 1); boundingBoxes = cat(1, stats.BoundingBox); for i = 1:num characters{i} = stats(i).Image; end % 对字符进行排序 [~, order] = sortrows(boundingBoxes, [1 -2]); sorted_characters = characters(order); % 使用montage显示所有字符图像 montage(character_images, 'Size', [1 num], 'BorderSize', [1 1], 'BackgroundColor', 'white');