我正在制作识别数字(OCR)的应用程序,所以我需要为它准备imamge。当我将照片拍到蓝色,绿色,黄色或其他颜色时没有问题,但是在OpenCV中灰度级后红色数字变得如此灰暗,这些数字无法识别。
阈值后的图像:
如你所见,红色数字消失后。
以下是我使用的代码片段:
mat.ConvertTo(mat, CvType.Cv8uc1);
Imgproc.CvtColor(mat, mat, Imgproc.ColorBgr2gray);
Imgproc.Threshold(mat, mat, 127, 255, Imgproc.ThreshBinary);
任何解决方案?
答案 0 :(得分:3)
正如我在评论中提到的,你可以对每个颜色通道R,G,B执行Otsu阈值。
蓝色通道的Otsu门槛:
绿色通道的Otsu门槛:
红色通道的Otsu阈值:
最后,我添加了以上所有内容以获得以下结果:
我只使用了以下功能:
cv2.threshold()
cv2.add()
<强>代码强>
import os
import cv2
import numpy as np
#--- performs Otsu threshold ---
def threshold(img, st):
ret, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv2.imwrite(os.path.join(path, 'res_' + str(st) + '.jpg'), thresh)
return thresh
path = r'C:\Users\Desktop'
filename = 'digits.jpg'
img = cv2.imread(os.path.join(path, filename))
img = cv2.resize(img, (0, 0), fx = 0.5, fy = 0.5) #--- resized the image because it was to big
cv2.imshow('Original', img)
#--- see each of the channels individually ---
cv2.imshow('b', img[:,:,0])
cv2.imshow('g', img[:,:,1])
cv2.imshow('r', img[:,:,2])
m1 = threshold(img[:,:,0], 1) #--- threshold on blue channel
m2 = threshold(img[:,:,1], 2) #--- threshold on green channel
m3 = threshold(img[:,:,2], 3) #--- threshold on red channel
#--- adding up all the results above ---
res = cv2.add(m1, cv2.add(m2, m3))
cv2.imshow('res', res)
cv2.imwrite(os.path.join(path, 'res.jpg'), res)
cv2.waitKey()
cv2.destroyAllWindows()
答案 1 :(得分:2)
@Jeru Luke的解决方案对于各种输入图像应该相当稳健。但是如果你需要原始速度,你可能会想到一个简单的亮度/对比度操作,然后进行全局阈值处理。
如果你使用计算上便宜的亮度和对比度,你可以让背景变成全黑,然后使用全局阈值来获得漂亮的二值化图像。
照片编辑器(Photoshop,Gimp等)经常使用±127的亮度/对比度。用于同时添加亮度(b)和对比度(c)的数学格式是
img =(1 + c / 127)* img +(b-c)
如果您可以从C#访问mat
,则可以使用cv.mat.convertTo功能:
cv.Mat.convertTo( OutputArray, cv.CV_8U, 1+c/127, b-c)
对于你的图像,我使用了b = -45和c = +45
然后转换为灰度和二值化(我在图像上使用了50的阈值)
<强>更新强>
OP被标记为C#。但是我们很多人都使用Python。在Python中,我们无法访问Mat。但是,我们可以使用cv2.addWeighted
函数:
dst = src1 * alpha + src2 * beta + gamma
如果我们设置beta = 0,那么这相当于cv.Mat.convertTo
缩放。这似乎比在Numpy中进行矩阵运算更快。 Numpy有点慢,因为我们必须做一些额外的事情来处理溢出。