Pekala, işte başka bir olası çözüm. Python ile çalıştığını biliyorum - C ++ ile çalışıyorum. Size bazı fikirler vereceğim ve umarım, isterseniz, bu yanıtı uygulayabilirsiniz.
Ana fikir, ön işlemeyi hiç kullanmamak (en azından ilk aşamada değil) ve bunun yerine her hedef karaktere odaklanmak, bazı özellikler elde etmek ve her blobe bu özelliklere göre filtre uygulamaktır .
Ön işleme kullanmaya çalışmıyorum çünkü: 1) Filtreler ve morfolojik aşamalar lekelerin kalitesini düşürebilir ve 2) hedef lekeleriniz, özellikle en boy oranı ve alan gibi , kullanabileceğimiz bazı özellikler sergiler .
Şuna bir bak, sayılar ve harflerin hepsi daha geniş olduğundan daha uzun görünüyor ... ayrıca, belirli bir alan değeri içinde değişiyor gibi görünüyor. Örneğin, "çok geniş" veya "çok büyük" nesneleri atmak istersiniz .
Fikir şu ki, önceden hesaplanmış değerlere girmeyen her şeyi filtreleyeceğim. Karakterleri (sayılar ve harfler) inceledim ve minimum, maksimum alan değerleri ve minimum en boy oranı (burada yükseklik ve genişlik arasındaki oran) ile geldim.
Algoritma üzerinde çalışalım. Görüntüyü okuyarak ve boyutların yarısına göre yeniden boyutlandırarak başlayın. Resminiz çok büyük. Gri tonlamaya dönüştürün ve otsu aracılığıyla ikili bir görüntü elde edin, işte sözde kod:
//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" );
Güzel. Bu görüntü ile çalışacağız. Her beyaz lekeyi incelemeniz ve bir "özellikler filtresi" uygulamanız gerekir . Her blob döngü döngü ve alan ve en boy oranı almak için istatistikleri ile bağlı bileşenleri kullanıyorum , C ++ bu aşağıdaki gibi yapılır:
//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…
};
Şimdi özellikler filtresini uygulayacağız. Bu sadece önceden hesaplanan eşiklerle bir karşılaştırmadır. Aşağıdaki değerleri kullandım:
Minimum Area: 40 Maximum Area:400
MinimumAspectRatio: 1
Döngünüzün içinde for
, geçerli blob özelliklerini bu değerlerle karşılaştırın. Testler pozitifse, damarı siyaha boyayabilirsiniz. for
Döngünün içinde devam ediyor :
//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 );
}
Döngüden sonra, filtrelenen görüntüyü oluşturun:
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];
}
}
Ve… işte bu kadar. Aradığınız şeye benzemeyen tüm öğeleri filtrelediniz. Algoritmayı çalıştırdığınızda şu sonucu elde edersiniz:
Ayrıca sonuçları daha iyi görselleştirmek için lekelerin Sınırlayıcı Kutularını buldum:
Gördüğünüz gibi, bazı unsurlar gözden kaçar. Aradığınız karakterleri daha iyi tanımlamak için "özellikler filtresini" daraltabilirsiniz. Biraz makine öğrenimi içeren daha derin bir çözüm, "ideal özellik vektörü" nin oluşturulmasını, damlalardan özelliklerin çıkarılmasını ve her iki vektörü de benzerlik ölçüsü ile karşılaştırmayı gerektirir. Sonuçları iyileştirmek için bazı işlem sonrası işlemler de uygulayabilirsiniz ...
Her neyse, dostum, sorununuz önemsiz veya kolay ölçeklenebilir değil ve ben size sadece fikirler veriyorum. Umarım çözümünüzü uygulayabilirsiniz.