Хорошо, вот еще одно возможное решение. Я знаю, что вы работаете с Python - я работаю с C ++. Я дам вам несколько идей и, надеюсь, если вы захотите, вы сможете реализовать этот ответ.
Основная идея заключается в том, чтобы вообще не использовать предварительную обработку (по крайней мере, на начальном этапе), а вместо этого сосредоточиться на каждом целевом символе, получить некоторые свойства и отфильтровать каждый BLOB-объект в соответствии с этими свойствами.
Я пытаюсь не использовать предварительную обработку, потому что: 1) фильтры и морфологические стадии могут ухудшить качество сгустков и 2) ваши целевые сгустки обладают некоторыми характеристиками, которые мы могли бы использовать, в основном: соотношение сторон и площадь .
Проверьте это, цифры и буквы кажутся выше, чем шире ... кроме того, они кажутся разными в пределах определенного значения площади. Например, вы хотите отбросить объекты "слишком широкие" или "слишком большие" .
Идея в том, что я буду фильтровать все, что не попадает в предварительно рассчитанные значения. Я изучил символы (цифры и буквы) и пришел с минимальными, максимальными значениями площади и минимальным соотношением сторон (здесь соотношение между высотой и шириной).
Давайте работать над алгоритмом. Начните с чтения изображения и изменения его размера до половины размеров. Ваше изображение слишком велико. Преобразовать в оттенки серого и получить двоичное изображение через отсу, вот в псевдокоде:
//Read input:
inputImage = imread( "diagram.png" );
//Resize Image;
resizeScale = 0.5;
inputResized = imresize( inputImage, resizeScale );
//Convert to grayscale;
inputGray = rgb2gray( inputResized );
//Get binary image via otsu:
binaryImage = imbinarize( inputGray, "Otsu" );
Круто. Мы будем работать с этим изображением. Вам нужно изучить каждый белый шарик и применить «фильтр свойств» . Я использую связанные компоненты со статистикой, чтобы пройти через каждый большой объект и получить его площадь и соотношение сторон, в C ++ это делается следующим образом:
//Prepare the output matrices:
cv::Mat outputLabels, stats, centroids;
int connectivity = 8;
//Run the binary image through connected components:
int numberofComponents = cv::connectedComponentsWithStats( binaryImage, outputLabels, stats, centroids, connectivity );
//Prepare a vector of colors – color the filtered blobs in black
std::vector<cv::Vec3b> colors(numberofComponents+1);
colors[0] = cv::Vec3b( 0, 0, 0 ); // Element 0 is the background, which remains black.
//loop through the detected blobs:
for( int i = 1; i <= numberofComponents; i++ ) {
//get area:
auto blobArea = stats.at<int>(i, cv::CC_STAT_AREA);
//get height, width and compute aspect ratio:
auto blobWidth = stats.at<int>(i, cv::CC_STAT_WIDTH);
auto blobHeight = stats.at<int>(i, cv::CC_STAT_HEIGHT);
float blobAspectRatio = (float)blobHeight/(float)blobWidth;
//Filter your blobs…
};
Теперь мы применим фильтр свойств. Это всего лишь сравнение с заранее рассчитанными порогами. Я использовал следующие значения:
Minimum Area: 40 Maximum Area:400
MinimumAspectRatio: 1
Внутри вашего for
цикла сравните текущие свойства BLOB-объектов с этими значениями. Если тесты положительные, вы «рисуете» черную каплю. Продолжая внутри for
цикла:
//Filter your blobs…
//Test the current properties against the thresholds:
bool areaTest = (blobArea > maxArea)||(blobArea < minArea);
bool aspectRatioTest = !(blobAspectRatio > minAspectRatio); //notice we are looking for TALL elements!
//Paint the blob black:
if( areaTest || aspectRatioTest ){
//filtered blobs are colored in black:
colors[i] = cv::Vec3b( 0, 0, 0 );
}else{
//unfiltered blobs are colored in white:
colors[i] = cv::Vec3b( 255, 255, 255 );
}
После цикла создайте отфильтрованное изображение:
cv::Mat filteredMat = cv::Mat::zeros( binaryImage.size(), CV_8UC3 );
for( int y = 0; y < filteredMat.rows; y++ ){
for( int x = 0; x < filteredMat.cols; x++ )
{
int label = outputLabels.at<int>(y, x);
filteredMat.at<cv::Vec3b>(y, x) = colors[label];
}
}
И ... вот и все. Вы отфильтровали все элементы, которые не похожи на то, что вы ищете. Запустив алгоритм вы получите такой результат:
Я также нашел Bounding Boxs от BLOB-объектов, чтобы лучше визуализировать результаты:
Как видите, некоторые элементы не обнаружены. Вы можете уточнить «фильтр свойств», чтобы лучше идентифицировать символы, которые вы ищете. Более глубокое решение, включающее немного машинного обучения, требует построения «идеального вектора признаков», извлечения признаков из BLOB-объектов и сравнения обоих векторов с помощью меры сходства. Вы можете также применить некоторые пост -переработкой улучшить результаты ...
Как бы то ни было, чувак, твоя проблема не просто и не легко масштабируема, и я просто даю тебе идеи. Надеюсь, вы сможете реализовать свое решение.