这个想法很简单。使用 morphology 来隔离您要检测的文本。使用此图像,创建一个遮罩以删除输入图像中的感兴趣区域并生成最终图像。全部通过形态学。我的答案在C++,但是实现起来真的很简单:
//Read input image:
std::string imagePath = "C://opencvImages//commentImage.png";
cv::Mat imageInput= cv::imread( imagePath );
//Convert it to grayscale:
cv::Mat grayImg;
cv::cvtColor( imageInput, grayImg, cv::COLOR_BGR2GRAY );
//Get binary image via Otsu:
cv::threshold( grayImg, grayImg, 0, 255 , cv::THRESH_OTSU );
到目前为止,您已经生成了二进制图像。现在,让我们dilate 使用矩形结构元素 (SE) 比更高更宽的图像。我的想法是我想水平加入所有文本AND 垂直(只是一点点)。如果您看到输入图像,“TEST132212” 文本似乎与评论稍有分离,似乎足以在dilate 操作中幸存下来。让我们看看,在这里,我使用大小为 9 x 6 的 SE 和 2 迭代:
cv::Mat morphKernel = cv::getStructuringElement( cv::MORPH_RECT, cv::Size(9, 6) );
int morphIterations = 2;
cv::morphologyEx( grayImg, grayImg, cv::MORPH_DILATE, morphKernel, cv::Point(-1,-1), morphIterations );
这是结果:
我在原始评论所在的位置找到了一个独特的块 - 很好!现在,这是图像中最大的斑点。如果我将它减去原始二进制图像,我应该生成一个 mask,它将成功隔离所有不是“评论”blob 的东西:
cv::Mat bigBlob = findBiggestBlob( grayImg );
我明白了:
现在,二进制掩码代:
cv::Mat binaryMask = grayImg - bigBlob;
//Use the binaryMask to produce the final image:
cv::Mat resultImg;
imageInput.copyTo( resultImg, binaryMask );
生成蒙版图像:
现在,您应该注意到findBiggestBlob 函数。这是我创建的一个函数,它返回二进制图像中最大的 blob。这个想法只是计算输入图像中的所有轮廓,计算它们的面积并存储具有最大面积的轮廓。这是C++ 的实现:
//Function to get the largest blob in a binary image:
cv::Mat findBiggestBlob( cv::Mat &inputImage ){
cv::Mat biggestBlob = inputImage.clone();
int largest_area = 0;
int largest_contour_index=0;
std::vector< std::vector<cv::Point> > contours; // Vector for storing contour
std::vector<cv::Vec4i> hierarchy;
// Find the contours in the image
cv::findContours( biggestBlob, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
for( int i = 0; i< (int)contours.size(); i++ ) {
//Find the area of the contour
double a = cv::contourArea( contours[i],false);
//Store the index of largest contour:
if( a > largest_area ){
largest_area = a;
largest_contour_index = i;
}
}
//Once you get the biggest blob, paint it black:
cv::Mat tempMat = biggestBlob.clone();
cv::drawContours( tempMat, contours, largest_contour_index, cv::Scalar(0),
CV_FILLED, 8, hierarchy );
//Erase the smaller blobs:
biggestBlob = biggestBlob - tempMat;
tempMat.release();
return biggestBlob;
}
编辑:自从发布答案以来,我一直在学习Python。这是Python 等效于C++ 代码:
import cv2
import numpy as np
# Set image path
path = "D://opencvImages//"
fileName = "commentImage.png"
# Read Input image
inputImage = cv2.imread(path+fileName)
# Convert BGR to grayscale:
grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
# Threshold via Otsu + bias adjustment:
threshValue, binaryImage = cv2.threshold(grayscaleImage, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Set kernel (structuring element) size:
kernelSize = (9, 6)
# Set operation iterations:
opIterations = 2
# Get the structuring element:
morphKernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernelSize)
# Perform Dilate:
openingImage = cv2.morphologyEx(binaryImage, cv2.MORPH_DILATE, morphKernel, None, None, opIterations, cv2.BORDER_REFLECT101)
# Find the big contours/blobs on the filtered image:
biggestBlob = openingImage.copy()
contours, hierarchy = cv2.findContours(biggestBlob, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
contoursPoly = [None] * len(contours)
boundRect = []
largestArea = 0
largestContourIndex = 0
# Loop through the contours, store the biggest one:
for i, c in enumerate(contours):
# Get the area for the current contour:
currentArea = cv2.contourArea(c, False)
# Store the index of largest contour:
if currentArea > largestArea:
largestArea = currentArea
largestContourIndex = i
# Once you get the biggest blob, paint it black:
tempMat = biggestBlob.copy()
# Draw the contours on the mask image:
cv2.drawContours(tempMat, contours, largestContourIndex, (0, 0, 0), -1, 8, hierarchy)
# Erase the smaller blobs:
biggestBlob = biggestBlob - tempMat
# Generate the binary mask:
binaryMask = openingImage - biggestBlob
# Use the binaryMask to produce the final image:
resultImg = cv2.bitwise_and(inputImage, inputImage, mask = binaryMask)
cv2.imshow("Result", resultImg)
cv2.waitKey(0)