我需要提取下图中显示的千克(kg)值:
我手动裁剪图像以隔离文本部分,并应用了多种图像处理技术,例如灰度转换、阈值处理、高斯模糊和膨胀。然而,结果并没有我想象的那么清晰,Tesseract OCR 无法读取它们。以下是一些处理后的图像:
我目前正在使用 EmguCV 和 Tesseract,并尝试了各种 tesseract 模型,包括
tessdata_best
(英文)、lets
和 letsgodigital
。不幸的是,这些尝试都没有成功。
使用的具体语言或库并不重要,因为我计划将解决方案转换为 C#。最终的实现将是使用 Xamarin.Forms 的移动应用程序。
以下是我使用但没有成功的示例方法:
public static void Apply()
{
var folderName = "letsgodigital";
var dataname = "letsgodigital";
string tesseractPath = @$"./{folderName}";
string imagePath = @"img.jpg";
Mat image = CvInvoke.Imread(imagePath, ImreadModes.Color);
Mat blurredImg = new Mat();
CvInvoke.Blur(image, blurredImg, new Size(9, 9), new Point(-1, -1));
Mat grayImg = new Mat();
CvInvoke.CvtColor(blurredImg, grayImg, ColorConversion.Bgr2Gray);
Mat binaryImg = new Mat();
CvInvoke.Threshold(grayImg, binaryImg, 122, 255, ThresholdType.Binary);
binaryImg.Save("full_pannel_bw.png");
using (var engine = new TesseractEngine(tesseractPath, dataname, EngineMode.Default))
{
engine.DefaultPageSegMode = PageSegMode.SingleLine;
using (var img = Pix.LoadFromFile("full_pannel_bw.png"))
{
using (var page = engine.Process(img))
{
string text = page.GetText();
Console.WriteLine("tesseract got: \"{0}\"", text.Trim());
}
}
}
}
编辑我的最终流程 但 tesseract 无法读取它。我得到空文本。现在我正在尝试使图像上的文字变暗
static void loggg()
{
Mat img = CvInvoke.Imread("5.jpg", ImreadModes.Color);
VectorOfMat channels = new VectorOfMat();
CvInvoke.Split(img, channels);
Mat redChannel = new Mat();
CvInvoke.Subtract(channels[2], channels[1], redChannel);
CvInvoke.Subtract(redChannel, channels[0], redChannel);
CvInvoke.Threshold(redChannel, redChannel, 40, 255, ThresholdType.Binary);
Mat invertedRedChannel = new Mat();
CvInvoke.BitwiseNot(redChannel, invertedRedChannel);
Mat morphKernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(2, 2), new Point(-1, -1));
CvInvoke.MorphologyEx(invertedRedChannel, invertedRedChannel, MorphOp.Close, morphKernel, new Point(-1, -1), 1, BorderType.Constant, new MCvScalar(255));
Mat dilateKernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(1, 1), new Point(-1, -1));
CvInvoke.Dilate(invertedRedChannel, invertedRedChannel, dilateKernel, new Point(-1, -1), 1, BorderType.Constant, new MCvScalar(0));
invertedRedChannel.Save("darker_red_text.jpg");
img.Dispose();
redChannel.Dispose();
invertedRedChannel.Dispose();
channels.Dispose();
}
首先对图片进行一些评论:
建议:
显示的文字明亮且呈红色。您可以利用这两个属性。所以你会选择图片的红色通道,然后选择阈值。
这只是红色通道:
我将应用“伽玛”映射,它是非线性的。这是一种可以尝试的事情,如果结果更好的话就保留它。如果它是线性的,它不会做太多事情,无论如何都会达到一个阈值(稍后出现)。
面板的深色 LED 看起来仍然相当亮(水平约为 0.25),但不如以前那么亮(约为 0.5)。人们可以应用替代或附加映射来使面板的黑暗部分变得更暗。
这已经构成了某种阈值......手动选取的值。
现在您还可以看到 LED 以及字母中它们之间的空格。我将应用低通滤波器来平滑它。这将有助于阈值处理,因为这些“异常值”的字母内部和外部不会有“噪音”。
对于阈值处理,尝试 Otsu 等自动算法通常是个好主意。在解决这个问题时,大津经常给我一些导致字母连接的阈值,所以我大部分时间都使用手动选择的阈值。通过额外的对比度拉伸,所有字母之间实际上只留下黑色(见最后一张图片),大津“工作”得足够好。
我认为即使对于简单的旧 Tesseract OCR 来说,这看起来也足够好了。如果需要反转,就反转即可。
这里有一些 Python,使用 OpenCV 函数,即使在第三方 C# 绑定中,这些函数也应该是等效的。
我立即转换为浮点数。如果我超出“通常”值范围(即值可以低于 0 并超过 255/1.0),这可以防止数字被剪切或环绕。这对于一些数学计算也很方便。
imshow()
将浮点数解释为从 0.0 到 1.0 的范围,但 imwrite()
只是转换为整数,因此您必须缩小范围。
im = cv.imread("QsvdNqcn.jpg")
# convert to float32 and scale to 0.0 .. 1.0
im = im * np.float32(1/255) # Mat::convertTo() with rtype=CV_32F and alpha=1.0/255.0
# getting a region
(x,y,w,h) = 763, 1281, 1167, 388
im = im[y:y+h, x:x+w] # Mat::operator()(cv::Rect)
(blue, green, red) = cv.split(im)
red_linear = red ** (1/0.45) # cv::pow()
# more contrast stretching to make "dark" parts darker
vmin, vmax = 0.7, 1.0
red_linear = (red_linear - vmin) / (vmax - vmin) # cv::Mat in C++ supports such expressions too
lowpassed = cv.GaussianBlur(red_linear, None, sigmaX=4.0)
(th, mask) = cv.threshold(lowpassed, 0.25, 1.0, cv.THRESH_BINARY)
# with Otsu, that'd take converting back to uint8 ranged 0..255
# (th, mask) = cv.threshold(np.clip(lowpassed * 255, 0, 255).astype(np.uint8), 128, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)