Добре, ось ще одне можливе рішення. Я знаю, що ви працюєте з Python - я працюю з C ++. Я дам вам кілька ідей і сподіваюся, якщо ви цього захочете, ви зможете реалізувати цю відповідь.
Основна ідея - взагалі не використовувати попередню обробку (принаймні, не на початковій стадії), а замість цього зосередитись на кожному цільовому символі, отримати деякі властивості та фільтрувати кожну крапку відповідно до цих властивостей.
Я намагаюся не використовувати попередню обробку, тому що: 1) Фільтри та морфологічні стадії можуть погіршити якість крапель і 2) здається, що у ваших цільових крапель є деякі характеристики, які ми могли б використовувати, головним чином: співвідношення сторін та площа .
Перевірте, цифри та букви виглядають вище, ніж ширші ... крім того, вони здаються різними в межах певного значення області. Наприклад, ви хочете відкинути об'єкти "занадто широкі" або "занадто великі" .
Ідея полягає в тому, що я фільтрую все, що не належить до попередньо обчислених значень. Я вивчив символи (цифри та літери) і прийшов із мінімальними, максимальними значеннями площі та мінімальним співвідношенням сторін (тут співвідношення між висотою та шириною).
Давайте попрацюємо над алгоритмом. Почніть з читання зображення і розміру його на половину розмірів. Ваш образ занадто великий. Перетворити в масштаб сірого та отримати бінарне зображення через otsu, ось у псевдокоді:
//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
циклу порівняйте поточні властивості блобу з цими значеннями. Якщо тести позитивні, ви "фарбуєте" крапку в чорний колір. Продовжуючи всередині 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];
}
}
І ... це майже все. Ви відфільтрували всі елементи, не схожі на те, що шукаєте. Запустивши алгоритм, ви отримаєте такий результат:
Крім того, я знайшов обмежувальні коробки крапель, щоб краще візуалізувати результати:
Як бачите, деякі елементи виявляються пропущеними. Ви можете вдосконалити "фільтр властивостей", щоб краще визначити шуканих символів. Більш глибоке рішення, що передбачає трохи машинного навчання, вимагає побудови "ідеального вектора ознак", вилучення функцій з крапель і порівняння обох векторів за допомогою міри подібності. Ви можете також застосувати деякі пост -перероблення поліпшити результати ...
Що б не було, чоловіче, твоя проблема не є дрібницею і не легко масштабується, і я просто даю тобі ідеї. Сподіваємось, ви зможете реалізувати своє рішення.