我有几个彩色图像的样本,我应该变成二进制。我使用自适应阈值获得了最佳结果。
这些数字非常好,定义明确,但周围很嘈杂,例如,将每个数字分开的这些“垂直线”最终被读作OCR工具的数字1。
然后我注意到数字周围的图像很干净。我想如果我只能剪掉数字(在制作黑白图片之前或之后?)然后将这些数字“粘贴”为白色背景。
我尝试应用侵蚀和扩张,但仍有许多剩余的“点”。如果我可以做我正在考虑的事情(上图),它会减少侵蚀/扩张并增加切割前数字周围的“清洁”,我不知道。
这可能吗?我有道理吗?如果是,我怎么能用OpenCV做到这一点?有什么建议吗?
我正在使用的一些图片:
注意:上面的图片没有经过侵蚀和/或扩张过程,只有自适应阈值处理。
更新
@ Mahm00d,我尝试了你用第一张图片说的话,我得到了下面的图片,这是非常好的,但前两个数字的反射问题仍在继续。有没有什么办法解决这一问题?我应用了自适应阈值,但图像仍然很大。
GaussianBlur +带OTSU标志的阈值:
GaussianBlur +自适应阈值:
答案 0 :(得分:3)
在进行阈值处理和形态学处理之前,首先使用一些去噪技术,比如高斯/中值模糊通常会很好:
(Java中的代码)
Imgproc.cvtColor(inputMat, gMat, Imgproc.COLOR_RGB2GRAY);
// Gaussian blur : 21x21 window, sigma = 50.0 (select these accordignly)
Imgproc.GaussianBlur(gMat, gMat, new Size(21.0, 21.0), 50.0);
// Otsu thresholding (or any other thresholding techinique...)
Imgproc.threshold(gMat, gMat, 0, 255, Imgproc.THRESH_OTSU | Imgproc.THRESH_BINARY);
你的输出:
以上代码输出:
<强>更新强>
这些问题通常需要使用参数值来获得良好的结果并获得最佳值。在第二个图像的情况下,这是我使用的代码(自适应阈值)以获得更好的结果:
Imgproc.GaussianBlur(inImg, inImg, new Size(21.0, 21.0), 50.0);
Imgproc.adaptiveThreshold(inImg, inImg, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 111, -20);
结果:
当然它并不完美,但至少反射被删除了。此外,形态学过程可以帮助产生更好的结果。
答案 1 :(得分:2)
一种解决方案是应用扩张和侵蚀,找到所有小于X像素的轮廓并用白色填充它们:
int main()
{
// Load the image as a Grayscale
Mat image = imread("image.jpg", CV_LOAD_IMAGE_GRAYSCALE);
// Threshold the image
image = image > 120;
// Create bigger image with image width and height + 10 pixels
Mat image_big = Mat::zeros( image.size().height + 10, image.size().width + 10, CV_8UC1 );
// Set bigger image to be all white
image_big.setTo(255);
Mat image_big_copy;
// This may vary, you must find it for yourself
// Dilate image 4 times and erode once
dilate(image, image, Mat(), Point(-1,-1), 4);
erode(image, image, Mat(), Point(-1,-1));
// Copy image in the center of bigger image so you left 5px around image blank/white
// Create a new ROI that points to center of the bigger image
Mat image_big_roi = image_big( Rect(Point(5, 5), Size(image.size())) );
// Copy image to the bigger image ROI
addWeighted(image_big_roi, 0., image, 1., 0., image_big_roi);
// Create a data copy of image_big
image_big.copyTo(image_big_copy);
// Find all contours in a given image and store them in contours
vector<vector<Point> > contours;
findContours(image_big_copy, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
for( int i = 0; i < contours.size(); i++ )
{
// This is your condition to filter out unwanted contours etc.
// For every contour if its area is bigger/smaller than the sum of pixels
if ( fabs(contourArea(Mat(contours[i]))) < 800 )
{
// Fill a contour with white color
drawContours(image_big, contours, i, Scalar(255), CV_FILLED);
}
}
imshow("Image original", image);
imshow("Image edited", image_big);
waitKey(0);
return 0;
}
原始图片:
后: