【问题标题】:OpenCV grayscale ignore red colorOpenCV灰度忽略红色
【发布时间】:2018-11-18 19:33:46
【问题描述】:

我正在制作识别数字 (OCR) 的应用程序,因此我需要为它准备 imamge。当我把照片拍成蓝色、绿色、黄色或其他颜色时没有问题,但红色数字在 OpenCV 中灰度后变得很灰,这些数字变得无法识别。

原图:

灰度后的图像(黄色和红色数字):

阈值后的图像:

如您所见,之后红色数字消失了。

这是我使用的代码片段:

mat.ConvertTo(mat, CvType.Cv8uc1);
Imgproc.CvtColor(mat, mat, Imgproc.ColorBgr2gray);
Imgproc.Threshold(mat, mat, 127, 255, Imgproc.ThreshBinary);

有什么解决办法吗?

【问题讨论】:

  • 尝试不同的阈值或尝试分别使用每个 RGB 通道。看起来很有希望。
  • 您的问题是,纯红色的亮度非常低 (~76),而周围的灰色约为 50,因此这些值之间没有太大差异,尤其是对于阈值。跨度>

标签: c# android opencv image-processing xamarin.android


【解决方案1】:

@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 有点慢,因为我们必须做一些额外的事情来处理溢出。

【讨论】:

  • 精彩见解 +1
  • 你能给我这个公式适用于浅蓝色背景上的深蓝色数字吗?
  • 对于浅色背景上的深色数字,您必须调整亮度和对比度,直到背景消失。然后你会想要转换为灰度和二值化。当您二值化时,您需要反转颜色,以便您现在的黑色数字变为白色,而白色背景变为黑色。
【解决方案2】:

正如我在 cmets 中提到的,您可以对每个颜色通道 R、G、B 执行 Otsu 阈值。

蓝色通道的大津阈值:

绿色通道的大津阈值:

红色通道的大津阈值:

最后我添加了以上所有内容,得到以下结果:

我只使用了以下功能:

  1. cv2.threshold()

  2. 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()

【讨论】:

  • 能否分别提供阈值所有通道的 Python 代码?
猜你喜欢
  • 2017-03-02
  • 1970-01-01
  • 1970-01-01
  • 2012-05-28
  • 2011-12-03
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
  • 2016-09-09
相关资源
最近更新 更多