利用投影法进行字符分割

目录(?)[+]

1.概述

字符分割有很多方法,但并不是每一种方法是万能的,那么就需要根据自己的需要来分析。例如:我现在项目的需求是将一串编号给切分开来。查了网上的资料和文献,大致适合项目的有两种方法:投影分割法连通域分割法。当然还有其他的一些改进的算法,今天就不作深入讨论,以后研究了再分享。

2.分析

投影法的原理其实很简单,利用二值化图片的像素的分布直方图进行分析,从而找出相邻字符的分界点进行分割。

投影

上图其实已经看的很明白,投影所反应的就是在垂直方向上数字区域像素个数。接下来我们只需判断投影的每一列,即可找出分割点。

3.实现过程

首先,定义一个数组用来储存每一列像素中白色像素的个数。

    int perPixelValue;//每个像素的值
    int* projectValArry = new int[width];//创建一个用于储存每列白色像素个数的数组
    memset(projectValArry, 0, width*4);//必须初始化数组
   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

然后,遍历二值化后的图片,将每一列中白色的(也就是数字区域)像素记录在数组中。

    //遍历每一列的图像灰度值,查找每一行255的值
    for (int col = 0; col < width; ++col)
    {
        for (int row = 0; row < height; ++row)
        {
            perPixelValue = binImg.at<uchar>(row, col);
            if (perPixelValue == 255)//如果是黑底白字
            {
                projectValArry[col]++;
            }
        }
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

最后,根据数组里的灰度值画出投影图

    /*新建一个Mat用于储存投影直方图并将背景置为白色*/
    Mat verticalProjectionMat(height, width, CV_8UC1);
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            perPixelValue = 255;  //背景设置为白色。   
            verticalProjectionMat.at<uchar>(i, j) = perPixelValue;
        }
    }

    /*将直方图的曲线设为黑色*/
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < projectValArry[i]; j++)
        {
            perPixelValue = 0;  //直方图设置为黑色  
            verticalProjectionMat.at<uchar>(height - 1 - j, i) = perPixelValue;
        }
    }
    imshow("【投影】",verticalProjectionMat);
    delete[] projectValArry;//不要忘了删除数组空间
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

有了投影图做切割就很容易了,其实最主要的就是那个储存灰度值的数组,下面就需要根据这个数组的内容来找到相邻字符间的分割点。

    vector<Mat> roiList;//用于储存分割出来的每个字符
    int startIndex = 0;//记录进入字符区的索引
    int endIndex = 0;//记录进入空白区域的索引
    bool inBlock = false;//是否遍历到了字符区内
    for (int i = 0; i < srcImg.cols; ++i)
    {
        if (!inBlock && projectValArry[i] != 0)//进入字符区了
        {
            inBlock = true;
            startIndex = i;
            cout << "startIndex is " << startIndex << endl;
        }
        else if (projectValArry[i] == 0 && inBlock)//进入空白区了
        {
            endIndex = i;
            inBlock = false;    
            Mat roiImg = srcImg(Range(0,srcImg.rows),Range(startIndex,endIndex+1));
            roiList.push_back(roiImg);
        }
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

最后来看下效果图: 
效果图

4.总结

做图像分割的时候要选择合适的方法,例如我这张样本图的布局是左右型,就适合用垂直投影的方法,反之若是上下型,则做水平投影即可。若图像内的字符是纵横交错的话就需要先垂直投影分割再水平分割,或者采用连通域分割法,取出字符范围。

<think>好的,用户想用MATLAB通过垂直投影法实现字符分割,需要方法和代码示例。首先,我得回忆一下垂直投影法的基本原理。垂直投影法主要是通过统计图像每一列的像素值,找到波谷位置来进行分割。这适用于字符之间有明显间隔的情况,比如车牌识别。 接下来,我需要整理实现步骤。首先,图像预处理是必要的。用户可能需要将彩色图像转为灰度,然后二值化,确保背景为0,字符为1。接下来是垂直投影统计,对每一列的非零像素进行求和,得到投影直方图。然后,分析投影数据,找到波谷点,这些点就是字符之间的分割位置。 然后,我得考虑如何将这些步骤转化为MATLAB代码。可能需要用到im2bw或者imbinarize函数进行二值化,sum函数统计每列像素和。波谷检测可能需要找局部最小值,这里可以通过比较相邻点来判断。另外,处理连续波谷或者噪声的情况,可能需要设置阈值,比如投影值小于某个数才视为波谷。 用户提供的引用中有两个MATLAB相关的例子,虽然一个是函数add,可能和投影无关,但另一个提到了垂直投影分割,可能需要参考如何处理投影数据。不过用户提供的代码示例可能不够直接,需要自己构造。 还要注意代码的健壮性,比如处理不同的图像尺寸,二值化方法的选择(比如Otsu算法),以及分割后的区域可能存在粘连的情况,这时候可能需要进一步处理,比如水平投影或者形态学操作,但用户当前的问题可能只需要垂直投影部分。 最后,生成相关问题时要考虑用户可能的后续需求,比如优化分割效果、处理复杂背景、多行字符等。确保回答结构清晰,步骤明确,代码可运行,并且给出实际应用的例子,比如车牌识别,这样用户能更好地理解应用场景。</think>### MATLAB垂直投影法字符分割实现方法 通过垂直投影法实现字符分割的核心是统计图像在垂直方向的像素分布,利用字符间距的波谷位置确定分割点。以下是详细步骤和代码实现: --- #### **一、实现步骤** 1. **图像预处理** - 转换为灰度图:$gray = rgb2gray(img)$ - 二值化处理:$bw = imbinarize(gray)$(默认使用Otsu算法) - 反色处理:若背景为白色,需反转颜色使字符为1、背景为0($bw = ~bw$) 2. **垂直投影统计** - 统计每列非零像素数量:$projection = sum(bw, 1)$ 3. **波谷检测** - 遍历投影数据,找到局部最小值点(波谷),即分割位置 - 过滤过小的波谷(避免噪声干扰) 4. **字符分割** - 根据波谷位置划分字符区域 - 提取每个字符的子图像 --- #### **二、代码示例** ```matlab function charRegions = vertical_projection_segmentation(img) % 1. 图像预处理 gray = rgb2gray(img); bw = imbinarize(gray); bw = ~bw; % 确保字符为白色(像素值1),背景为黑色(像素值0) % 2. 垂直投影统计 projection = sum(bw, 1); % 3. 波谷检测(分割点) splitPoints = []; for i = 2:length(projection)-1 if projection(i) < projection(i-1) && projection(i) < projection(i+1) splitPoints = [splitPoints, i]; end end % 4. 合并相邻分割点并提取字符 minGap = 5; % 最小字符间距阈值 splitPoints = [0, splitPoints, size(img,2)]; % 添加起始和结束点 charRegions = {}; for i = 2:length(splitPoints) if splitPoints(i) - splitPoints(i-1) > minGap xStart = splitPoints(i-1) + 1; xEnd = splitPoints(i) - 1; charRegions{end+1} = img(:, xStart:xEnd, :); % 提取字符区域 end end end ``` --- #### **三、关键参数说明** 1. **minGap**:控制最小字符间距,避免将窄字符错误分割 2. **投影滤波**:可添加中值滤波平滑投影曲线(`projection = medfilt1(projection, 3)`) 3. **复杂背景处理**:需结合形态学操作(如腐蚀、膨胀)去除噪声[^1] --- #### **四、实际应用示例** **车牌字符分割**(参考引用[1][^1]): ```matlab % 读取车牌图像 plateImg = imread('license_plate.jpg'); % 调用分割函数 characters = vertical_projection_segmentation(plateImg); % 显示分割结果 figure; for i = 1:length(characters) subplot(1, length(characters), i); imshow(characters{i}); end ``` --- #### **五、常见问题优化** 1. **粘连字符处理**:结合水平投影或轮廓分析进一步分割 2. **倾斜校正**:通过Hough变换检测倾斜角度并旋转图像 3. **光照不均**:使用自适应二值化(如`imbinarize(gray, 'adaptive')`) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值