Этого очень трудно добиться без справочных данных или образца однородности. Однако я разработал рекомендацию по анализу отношения среднего отношения сигнал / шум ( сигнал / шум ) изображения. Алгоритм делит входное изображение на заданное количество «субизображений» на основе заданного размера ядра, чтобы независимо оценивать их для локального SNR. Вычисленные SNR для каждого субизображения затем усредняются для получения индикатора для глобального SNR изображения.
Вам нужно будет тщательно протестировать этот подход, однако он показывает многообещающие результаты на следующих трех изображениях, создавая AvgSNR
;
Изображение # 1 - AvgSNR = 0,9
Изображение # 2 - AvgSNR = 7,0
Изображение №3 - AvgSNR = 0,6
ПРИМЕЧАНИЕ: Посмотрите, как "чистый" контрольный образ дает намного больше AvgSNR
.
Единственная переменная, которую следует учитывать, - это размер ядра. Я бы рекомендовал оставить это значение на размер, который будет поддерживать даже самые маленькие из ваших потенциальных входных изображений. Квадрат 30 пикселей, вероятно, будет подходящим для r много изображений.
Я прилагаю свой тестовый код с аннотацией:
class Program
{
static void Main(string[] args)
{
// List of file names to load.
List<string> fileNames = new List<string>()
{
"IifXZ.png",
"o1z7p.jpg",
"NdQtj.jpg"
};
// For each image
foreach (string fileName in fileNames)
{
// Determine local file path
string path = Path.Combine(Environment.CurrentDirectory, @"TestImages\", fileName);
// Load the image
Image<Bgr, byte> inputImage = new Image<Bgr, byte>(path);
// Compute the AvgSNR with a kernel of 30x30
Console.WriteLine(ComputeAverageSNR(30, inputImage.Convert<Gray, byte>()));
// Display the image
CvInvoke.NamedWindow("Test");
CvInvoke.Imshow("Test", inputImage);
while (CvInvoke.WaitKey() != 27) { }
}
// Pause for evaluation
Console.ReadKey();
}
static double ComputeAverageSNR(int kernelSize, Image<Gray, byte> image)
{
// Calculate the number of sub-divisions given the kernel size
int widthSubDivisions, heightSubDivisions;
widthSubDivisions = (int)Math.Floor((double)image.Width / kernelSize);
heightSubDivisions = (int)Math.Floor((double)image.Height / kernelSize);
int totalNumberSubDivisions = widthSubDivisions * widthSubDivisions;
Rectangle ROI = new Rectangle(0, 0, kernelSize, kernelSize);
double avgSNR = 0;
// Foreach sub-divions, calculate the SNR and sum to the avgSNR
for (int v = 0; v < heightSubDivisions; v++)
{
for (int u = 0; u < widthSubDivisions; u++)
{
// Iterate the sub-division position
ROI.Location = new Point(u * kernelSize, v * kernelSize);
// Calculate the SNR of this sub-division
avgSNR += ComputeSNR(image.GetSubRect(ROI));
}
}
avgSNR /= totalNumberSubDivisions;
return avgSNR;
}
static double ComputeSNR(Image<Gray, byte> image)
{
// Local varibles
double mean, sigma, snr;
// Calculate the mean pixel value for the sub-division
int population = image.Width * image.Height;
mean = CvInvoke.Sum(image).V0 / population;
// Calculate the Sigma of the sub-division population
double sumDeltaSqu = 0;
for (int v = 0; v < image.Height; v++)
{
for (int u = 0; u < image.Width; u++)
{
sumDeltaSqu += Math.Pow(image.Data[v, u, 0] - mean, 2);
}
}
sumDeltaSqu /= population;
sigma = Math.Pow(sumDeltaSqu, 0.5);
// Calculate and return the SNR value
snr = sigma == 0 ? mean : mean / sigma;
return snr;
}
}
ПРИМЕЧАНИЕ: Без ссылки невозможно различить естественную дисперсию / точность и «шум». Например, фон с высокой текстурой или сцена с несколькими однородными областями даст высокий AvgSNR
. Этот подход будет работать лучше всего, когда оцениваемая сцена состоит в основном из простых одноцветных поверхностей, таких как серверная или магазин. Например, трава может содержать большое количество текстуры и, следовательно, «шума».