OCR识别过程中,调用文档方向检测函数

在OCR开发过程中,比较头疼的是,收到的识别文件中含各式各样的文本,倾斜模糊、中文英文、其中文字是倒的也是一种比较复杂的识别类型。

我们以中文识别为例,判断中文文档是否颠倒的算法使用了一个简单的重心检测,它依赖于计算图像的重心位置,并假设颠倒的文档其重心会发生显著变化。然而,中文字符的上下对称性可能会导致重心检测并不总是可靠。因此,我们结合撇捺方向性检测上下结构检测,以提高对文档是否颠倒的识别精度。

算法优化步骤

  1. 重心检测:继续使用重心检测来判断整体字符的重心分布,尤其是当重心明显靠下时,可能表示文档颠倒。
  2. 撇捺方向检测:中文的撇捺方向具有显著的上下差异。我们通过统计撇(从左上到右下的斜线)和捺(从右上到左下的斜线)的数量差异,来帮助判断是否颠倒。
  3. 上下结构检测:中文字符中的上下结构(例如“家”、“票”等)在颠倒后会产生明显变化,通过分析字符中部的笔画密度来判断是否倒置。

具体代码

#include <windows.h>
#include <gdiplus.h>
#include <commdlg.h>  // 用于打开文件对话框
#include <iostream>
#include <vector>
#include <cmath>

#pragma comment (lib,"Gdiplus.lib")

using namespace Gdiplus;
using namespace std;

// 全局变量
HINSTANCE hInst;
LPCWSTR szTitle = L"中文文档方向检测";
LPCWSTR szWindowClass = L"DocumentDirectionApp";
Gdiplus::Bitmap* loadedImage = nullptr;
bool isInverted = false;

// 定义退出菜单ID
#define IDM_EXIT 1000

// 初始化GDI+
void InitGDIPlus(ULONG_PTR &gdiplusToken) {
    GdiplusStartupInput gdiplusStartupInput;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
}

// 关闭GDI+
void ShutdownGDIPlus(ULONG_PTR &gdiplusToken) {
    GdiplusShutdown(gdiplusToken);
}

// 打开文件对话框,选择图像文件
std::wstring OpenFileDialog(HWND hwnd) {
    wchar_t szFile[260] = { 0 };
    OPENFILENAME ofn = { 0 };
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile) / sizeof(*szFile);
    ofn.lpstrFilter = L"Image Files\0*.bmp;*.jpg;*.jpeg;*.png\0";
    ofn.nFilterIndex = 1;
    ofn.lpstrFileTitle = NULL;
    ofn.nMaxFileTitle = 0;
    ofn.lpstrInitialDir = NULL;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    if (GetOpenFileName(&ofn)) {
        return szFile;
    }

    return L"";
}

// 加载图像
Gdiplus::Bitmap* LoadImageFromFile(const std::wstring& filePath) {
    return new Gdiplus::Bitmap(filePath.c_str());
}

// 计算图像的重心位置
double CalculateCenterOfMass(Gdiplus::Bitmap* bmp) {
    int width = bmp->GetWidth();
    int height = bmp->GetHeight();
    int sumY = 0;
    int count = 0;

    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            Gdiplus::Color color;
            bmp->GetPixel(x, y, &color);
            int intensity = (color.GetR() + color.GetG() + color.GetB()) / 3;  // 转为灰度
            if (intensity < 128) {  // 假设灰度低于128为文字
                sumY += y;
                count++;
            }
        }
    }

    return (count > 0) ? (double)sumY / count : height / 2.0;
}

// 检测撇和捺的方向性
double CalculateStrokeOrientation(Gdiplus::Bitmap* bmp) {
    int width = bmp->GetWidth();
    int height = bmp->GetHeight();
    int leftTopToRightBottom = 0;  // 撇方向(左上到右下)
    int rightTopToLeftBottom = 0;  // 捺方向(右上到左下)

    for (int y = 1; y < height - 1; ++y) {
        for (int x = 1; x < width - 1; ++x) {
            Gdiplus::Color color;
            bmp->GetPixel(x, y, &color);
            int intensity = (color.GetR() + color.GetG() + color.GetB()) / 3;
            if (intensity < 128) {  // 假设灰度低于128为文字
                Gdiplus::Color colorLeftTop, colorRightBottom, colorRightTop, colorLeftBottom;
                bmp->GetPixel(x - 1, y - 1, &colorLeftTop);
                bmp->GetPixel(x + 1, y + 1, &colorRightBottom);
                bmp->GetPixel(x + 1, y - 1, &colorRightTop);
                bmp->GetPixel(x - 1, y + 1, &colorLeftBottom);

                int intensityLeftTop = (colorLeftTop.GetR() + colorLeftTop.GetG() + colorLeftTop.GetB()) / 3;
                int intensityRightBottom = (colorRightBottom.GetR() + colorRightBottom.GetG() + colorRightBottom.GetB()) / 3;
                int intensityRightTop = (colorRightTop.GetR() + colorRightTop.GetG() + colorRightTop.GetB()) / 3;
                int intensityLeftBottom = (colorLeftBottom.GetR() + colorLeftBottom.GetG() + colorLeftBottom.GetB()) / 3;

                if (intensityLeftTop < 128 && intensityRightBottom < 128) {
                    leftTopToRightBottom++;  // 统计撇方向
                }
                if (intensityRightTop < 128 && intensityLeftBottom < 128) {
                    rightTopToLeftBottom++;  // 统计捺方向
                }
            }
        }
    }

    return abs(leftTopToRightBottom - rightTopToLeftBottom);  // 返回撇和捺数量的差异
}

// 旋转图像180度
Gdiplus::Bitmap* RotateImage180(Gdiplus::Bitmap* bmp) {
    int width = bmp->GetWidth();
    int height = bmp->GetHeight();
    Gdiplus::Bitmap* rotatedBmp = new Gdiplus::Bitmap(width, height);

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            Gdiplus::Color color;
            bmp->GetPixel(x, y, &color);
            rotatedBmp->SetPixel(width - 1 - x, height - 1 - y, color);
        }
    }
    return rotatedBmp;
}

// 判断图像是否颠倒
bool IsImageInverted(Gdiplus::Bitmap* bmp) {
    // 计算正向图像的重心和撇捺方向
    double centerOfMassNormal = CalculateCenterOfMass(bmp);
    double strokeOrientationNormal = CalculateStrokeOrientation(bmp);

    // 将图像旋转180度
    Gdiplus::Bitmap* rotatedBmp = RotateImage180(bmp);

    // 计算旋转后的重心和撇捺方向
    double centerOfMassRotated = CalculateCenterOfMass(rotatedBmp);
    double strokeOrientationRotated = CalculateStrokeOrientation(rotatedBmp);

    // 释放旋转图像
    delete rotatedBmp;

    // 比较正向和旋转后图像的重心和撇捺差异
    double massDiff = abs(centerOfMassNormal - centerOfMassRotated);
    double strokeDiff = abs(strokeOrientationNormal - strokeOrientationRotated);

    // 如果重心或撇捺方向的差异大于阈值,认为图像颠倒
    return (massDiff > 50.0 || strokeDiff > 50.0);  // 阈值可根据需要调整
}

// 显示图像
void DisplayImage(HDC hdc, Gdiplus::Bitmap* bmp) {
    if (bmp) {
        Gdiplus::Graphics graphics(hdc);
        graphics.DrawImage(bmp, 10, 10, bmp->GetWidth(), bmp->GetHeight());
    }
}

// 窗口过程函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    PAINTSTRUCT ps;
抛转引玉,以示启发,需要哥们支持的,联系support@sinosecu.com.cn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值