Решения здесь:
None
в качестве значения по умолчанию (или nonce object
) и включите его, чтобы создать свои значения во время выполнения; или lambda
в качестве параметра по умолчанию и вызовите его в блоке try, чтобы получить значение по умолчанию (это то, что требуется для лямбда-абстракции). Второй вариант хорош, потому что пользователи функции могут проходить в вызываемом, который может уже существовать (например, type
)
да, это так. вычислить fft и проанализировать результат. Преобразование Фурье сообщает вам, какие частоты присутствуют в изображении. Если есть небольшое количество высоких частот, тогда изображение размыто.
Определение терминов «низкий» и «высокий» зависит от вас.
изменить: как указано в комментарии, если вы хотите, чтобы один поплавок, представляющий размытость данного изображения, вам нужно разработать подходящую метрику.
Ответ nikie дает такую метрику. Сконвертируйте изображение с ядром Лапласа:
1
1 -4 1
1
И используйте на выходе надежную максимальную метрику, чтобы получить число, которое вы можете использовать для порогового значения. Старайтесь избегать сглаживания изображений, прежде чем вычислять лапласиан, потому что вы обнаружите, что сглаженное изображение действительно размыто: -).
i реализовал его, используя fft в matlab и проверив гистограмму среднего значения вычисления fft и std, но также можно выполнить функцию
fa = abs(fftshift(fft(sharp_img)));
fb = abs(fftshift(fft(blured_img)));
f1=20*log10(0.001+fa);
f2=20*log10(0.001+fb);
figure,imagesc(f1);title('org')
figure,imagesc(f2);title('blur')
figure,hist(f1(:),100);title('org')
figure,hist(f2(:),100);title('blur')
mf1=mean(f1(:));
mf2=mean(f2(:));
mfd1=median(f1(:));
mfd2=median(f2(:));
sf1=std(f1(:));
sf2=std(f2(:));
Ответы выше объясняли многие вещи, но я думаю, что полезно сделать концептуальное различие.
Что делать, если вы снимаете совершенно нефокусированную картину размытого изображения?
Проблема обнаружения размытия является хорошей, если у вас есть ссылка . Если вам нужно разработать, например, систему автофокусировки, вы сравниваете последовательность изображений, сделанных с разной степенью размытия или сглаживания, и вы пытаетесь найти точку минимального размытия в этом наборе. Другими словами, вам нужно перекрестно ссылаться на различные изображения, используя один из описанных выше методов (в основном - с различными возможными уровнями уточнения подхода - поиск одного изображения с самым высоким высокочастотным контентом).
Я попробовал решение на основе лапласианского фильтра из этого сообщения. Это мне не помогло. Итак, я попробовал решение из этого сообщения , и это было хорошо для моего случая (но медленного):
import cv2
image = cv2.imread("test.jpeg")
height, width = image.shape[:2]
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
def px(x, y):
return int(gray[y, x])
sum = 0
for x in range(width-1):
for y in range(height):
sum += abs(px(x, y) - px(x+1, y))
Меньше размытого изображения имеет максимальное значение sum
!
Вы также можете настроить скорость и точность, изменив шаг, например
эту часть
for x in range(width - 1):
вы можете заменить на это
for x in range(0, width - 1, 10):
Спасибо, что за это великое предложение Лапласа. OpenCV docs указал мне в том же направлении: используя python, cv2 (opencv 2.4.10) и numpy ...
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
numpy.max(cv2.convertScaleAbs(cv2.Laplacian(gray_image,3)))
составляет от 0 до 255. Я обнаружил, что что-то более 200ish очень сосредоточено, и на 100 человек заметно размыто. max никогда не получает намного меньше 20, даже если он полностью размыт.
Я придумал совершенно другое решение. Мне нужно было проанализировать видео неподвижные кадры, чтобы найти самый острый в каждом (X) кадре. Таким образом, я обнаружил бы размытие движения и / или изображение с фокусом.
Я закончил использовать обнаружение Canny Edge, и я получил ОЧЕНЬ ОЧЕНЬ хорошие результаты почти с каждым видом видео (с использованием метода nikie, я проблемы с цифровыми видео VHS и тяжелыми чересстрочными видеороликами).
Я оптимизировал производительность, установив интересующую область (ROI) на исходное изображение.
Использование EmguCV:
//Convert image using Canny
using (Image<Gray, byte> imgCanny = imgOrig.Canny(225, 175))
{
//Count the number of pixel representing an edge
int nCountCanny = imgCanny.CountNonzero()[0];
//Compute a sharpness grade:
//< 1.5 = blurred, in movement
//de 1.5 à 6 = acceptable
//> 6 =stable, sharp
double dSharpness = (nCountCanny * 1000.0 / (imgCanny.Cols * imgCanny.Rows));
}
Код Matlab двух методов, опубликованных в высоко оцененных журналах (IEEE Transactions on Image Processing), доступен здесь: https://ivulab.asu.edu/software
проверить алгоритмы CPBDM и JNBM. Если вы проверите код, его не очень сложно портировать, и, кстати, он основан на методе Марциалиано как основной функции.
Во время некоторой работы с объективом с автоматической фокусировкой я наткнулся на этот очень полезный набор алгоритмов для обнаружения фокуса изображения . Он реализован в MATLAB, но большинство функций довольно легко переносить в OpenCV с помощью filter2D .
Это в основном обзорная реализация многих алгоритмов измерения фокусировки. Если вы хотите прочитать оригинальные статьи, в коде содержатся ссылки на авторов алгоритмов. В статье 2012 г. Пертуз и др. Анализ операторов фокусировки для формы из фокуса (SFF) дает отличный обзор всех этих показателей, а также их производительности (как с точки зрения скорости, так и точности применительно к SFF).
EDIT: Добавлен код MATLAB на всякий случай, когда ссылка замирает.
function FM = fmeasure(Image, Measure, ROI)
%This function measures the relative degree of focus of
%an image. It may be invoked as:
%
% FM = fmeasure(Image, Method, ROI)
%
%Where
% Image, is a grayscale image and FM is the computed
% focus value.
% Method, is the focus measure algorithm as a string.
% see 'operators.txt' for a list of focus
% measure methods.
% ROI, Image ROI as a rectangle [xo yo width heigth].
% if an empty argument is passed, the whole
% image is processed.
%
% Said Pertuz
% Abr/2010
if ~isempty(ROI)
Image = imcrop(Image, ROI);
end
WSize = 15; % Size of local window (only some operators)
switch upper(Measure)
case 'ACMO' % Absolute Central Moment (Shirvaikar2004)
if ~isinteger(Image), Image = im2uint8(Image);
end
FM = AcMomentum(Image);
case 'BREN' % Brenner's (Santos97)
[M N] = size(Image);
DH = Image;
DV = Image;
DH(1:M-2,:) = diff(Image,2,1);
DV(:,1:N-2) = diff(Image,2,2);
FM = max(DH, DV);
FM = FM.^2;
FM = mean2(FM);
case 'CONT' % Image contrast (Nanda2001)
ImContrast = inline('sum(abs(x(:)-x(5)))');
FM = nlfilter(Image, [3 3], ImContrast);
FM = mean2(FM);
case 'CURV' % Image Curvature (Helmli2001)
if ~isinteger(Image), Image = im2uint8(Image);
end
M1 = [-1 0 1;-1 0 1;-1 0 1];
M2 = [1 0 1;1 0 1;1 0 1];
P0 = imfilter(Image, M1, 'replicate', 'conv')/6;
P1 = imfilter(Image, M1', 'replicate', 'conv')/6;
P2 = 3*imfilter(Image, M2, 'replicate', 'conv')/10 ...
-imfilter(Image, M2', 'replicate', 'conv')/5;
P3 = -imfilter(Image, M2, 'replicate', 'conv')/5 ...
+3*imfilter(Image, M2, 'replicate', 'conv')/10;
FM = abs(P0) + abs(P1) + abs(P2) + abs(P3);
FM = mean2(FM);
case 'DCTE' % DCT energy ratio (Shen2006)
FM = nlfilter(Image, [8 8], @DctRatio);
FM = mean2(FM);
case 'DCTR' % DCT reduced energy ratio (Lee2009)
FM = nlfilter(Image, [8 8], @ReRatio);
FM = mean2(FM);
case 'GDER' % Gaussian derivative (Geusebroek2000)
N = floor(WSize/2);
sig = N/2.5;
[x,y] = meshgrid(-N:N, -N:N);
G = exp(-(x.^2+y.^2)/(2*sig^2))/(2*pi*sig);
Gx = -x.*G/(sig^2);Gx = Gx/sum(Gx(:));
Gy = -y.*G/(sig^2);Gy = Gy/sum(Gy(:));
Rx = imfilter(double(Image), Gx, 'conv', 'replicate');
Ry = imfilter(double(Image), Gy, 'conv', 'replicate');
FM = Rx.^2+Ry.^2;
FM = mean2(FM);
case 'GLVA' % Graylevel variance (Krotkov86)
FM = std2(Image);
case 'GLLV' %Graylevel local variance (Pech2000)
LVar = stdfilt(Image, ones(WSize,WSize)).^2;
FM = std2(LVar)^2;
case 'GLVN' % Normalized GLV (Santos97)
FM = std2(Image)^2/mean2(Image);
case 'GRAE' % Energy of gradient (Subbarao92a)
Ix = Image;
Iy = Image;
Iy(1:end-1,:) = diff(Image, 1, 1);
Ix(:,1:end-1) = diff(Image, 1, 2);
FM = Ix.^2 + Iy.^2;
FM = mean2(FM);
case 'GRAT' % Thresholded gradient (Snatos97)
Th = 0; %Threshold
Ix = Image;
Iy = Image;
Iy(1:end-1,:) = diff(Image, 1, 1);
Ix(:,1:end-1) = diff(Image, 1, 2);
FM = max(abs(Ix), abs(Iy));
FM(FM<Th)=0;
FM = sum(FM(:))/sum(sum(FM~=0));
case 'GRAS' % Squared gradient (Eskicioglu95)
Ix = diff(Image, 1, 2);
FM = Ix.^2;
FM = mean2(FM);
case 'HELM' %Helmli's mean method (Helmli2001)
MEANF = fspecial('average',[WSize WSize]);
U = imfilter(Image, MEANF, 'replicate');
R1 = U./Image;
R1(Image==0)=1;
index = (U>Image);
FM = 1./R1;
FM(index) = R1(index);
FM = mean2(FM);
case 'HISE' % Histogram entropy (Krotkov86)
FM = entropy(Image);
case 'HISR' % Histogram range (Firestone91)
FM = max(Image(:))-min(Image(:));
case 'LAPE' % Energy of laplacian (Subbarao92a)
LAP = fspecial('laplacian');
FM = imfilter(Image, LAP, 'replicate', 'conv');
FM = mean2(FM.^2);
case 'LAPM' % Modified Laplacian (Nayar89)
M = [-1 2 -1];
Lx = imfilter(Image, M, 'replicate', 'conv');
Ly = imfilter(Image, M', 'replicate', 'conv');
FM = abs(Lx) + abs(Ly);
FM = mean2(FM);
case 'LAPV' % Variance of laplacian (Pech2000)
LAP = fspecial('laplacian');
ILAP = imfilter(Image, LAP, 'replicate', 'conv');
FM = std2(ILAP)^2;
case 'LAPD' % Diagonal laplacian (Thelen2009)
M1 = [-1 2 -1];
M2 = [0 0 -1;0 2 0;-1 0 0]/sqrt(2);
M3 = [-1 0 0;0 2 0;0 0 -1]/sqrt(2);
F1 = imfilter(Image, M1, 'replicate', 'conv');
F2 = imfilter(Image, M2, 'replicate', 'conv');
F3 = imfilter(Image, M3, 'replicate', 'conv');
F4 = imfilter(Image, M1', 'replicate', 'conv');
FM = abs(F1) + abs(F2) + abs(F3) + abs(F4);
FM = mean2(FM);
case 'SFIL' %Steerable filters (Minhas2009)
% Angles = [0 45 90 135 180 225 270 315];
N = floor(WSize/2);
sig = N/2.5;
[x,y] = meshgrid(-N:N, -N:N);
G = exp(-(x.^2+y.^2)/(2*sig^2))/(2*pi*sig);
Gx = -x.*G/(sig^2);Gx = Gx/sum(Gx(:));
Gy = -y.*G/(sig^2);Gy = Gy/sum(Gy(:));
R(:,:,1) = imfilter(double(Image), Gx, 'conv', 'replicate');
R(:,:,2) = imfilter(double(Image), Gy, 'conv', 'replicate');
R(:,:,3) = cosd(45)*R(:,:,1)+sind(45)*R(:,:,2);
R(:,:,4) = cosd(135)*R(:,:,1)+sind(135)*R(:,:,2);
R(:,:,5) = cosd(180)*R(:,:,1)+sind(180)*R(:,:,2);
R(:,:,6) = cosd(225)*R(:,:,1)+sind(225)*R(:,:,2);
R(:,:,7) = cosd(270)*R(:,:,1)+sind(270)*R(:,:,2);
R(:,:,7) = cosd(315)*R(:,:,1)+sind(315)*R(:,:,2);
FM = max(R,[],3);
FM = mean2(FM);
case 'SFRQ' % Spatial frequency (Eskicioglu95)
Ix = Image;
Iy = Image;
Ix(:,1:end-1) = diff(Image, 1, 2);
Iy(1:end-1,:) = diff(Image, 1, 1);
FM = mean2(sqrt(double(Iy.^2+Ix.^2)));
case 'TENG'% Tenengrad (Krotkov86)
Sx = fspecial('sobel');
Gx = imfilter(double(Image), Sx, 'replicate', 'conv');
Gy = imfilter(double(Image), Sx', 'replicate', 'conv');
FM = Gx.^2 + Gy.^2;
FM = mean2(FM);
case 'TENV' % Tenengrad variance (Pech2000)
Sx = fspecial('sobel');
Gx = imfilter(double(Image), Sx, 'replicate', 'conv');
Gy = imfilter(double(Image), Sx', 'replicate', 'conv');
G = Gx.^2 + Gy.^2;
FM = std2(G)^2;
case 'VOLA' % Vollath's correlation (Santos97)
Image = double(Image);
I1 = Image; I1(1:end-1,:) = Image(2:end,:);
I2 = Image; I2(1:end-2,:) = Image(3:end,:);
Image = Image.*(I1-I2);
FM = mean2(Image);
case 'WAVS' %Sum of Wavelet coeffs (Yang2003)
[C,S] = wavedec2(Image, 1, 'db6');
H = wrcoef2('h', C, S, 'db6', 1);
V = wrcoef2('v', C, S, 'db6', 1);
D = wrcoef2('d', C, S, 'db6', 1);
FM = abs(H) + abs(V) + abs(D);
FM = mean2(FM);
case 'WAVV' %Variance of Wav...(Yang2003)
[C,S] = wavedec2(Image, 1, 'db6');
H = abs(wrcoef2('h', C, S, 'db6', 1));
V = abs(wrcoef2('v', C, S, 'db6', 1));
D = abs(wrcoef2('d', C, S, 'db6', 1));
FM = std2(H)^2+std2(V)+std2(D);
case 'WAVR'
[C,S] = wavedec2(Image, 3, 'db6');
H = abs(wrcoef2('h', C, S, 'db6', 1));
V = abs(wrcoef2('v', C, S, 'db6', 1));
D = abs(wrcoef2('d', C, S, 'db6', 1));
A1 = abs(wrcoef2('a', C, S, 'db6', 1));
A2 = abs(wrcoef2('a', C, S, 'db6', 2));
A3 = abs(wrcoef2('a', C, S, 'db6', 3));
A = A1 + A2 + A3;
WH = H.^2 + V.^2 + D.^2;
WH = mean2(WH);
WL = mean2(A);
FM = WH/WL;
otherwise
error('Unknown measure %s',upper(Measure))
end
end
%************************************************************************
function fm = AcMomentum(Image)
[M N] = size(Image);
Hist = imhist(Image)/(M*N);
Hist = abs((0:255)-255*mean2(Image))'.*Hist;
fm = sum(Hist);
end
%******************************************************************
function fm = DctRatio(M)
MT = dct2(M).^2;
fm = (sum(MT(:))-MT(1,1))/MT(1,1);
end
%************************************************************************
function fm = ReRatio(M)
M = dct2(M);
fm = (M(1,2)^2+M(1,3)^2+M(2,1)^2+M(2,2)^2+M(3,1)^2)/(M(1,1)^2);
end
%******************************************************************
Несколько примеров версий OpenCV:
// OpenCV port of 'LAPM' algorithm (Nayar89)
double modifiedLaplacian(const cv::Mat& src)
{
cv::Mat M = (Mat_<double>(3, 1) << -1, 2, -1);
cv::Mat G = cv::getGaussianKernel(3, -1, CV_64F);
cv::Mat Lx;
cv::sepFilter2D(src, Lx, CV_64F, M, G);
cv::Mat Ly;
cv::sepFilter2D(src, Ly, CV_64F, G, M);
cv::Mat FM = cv::abs(Lx) + cv::abs(Ly);
double focusMeasure = cv::mean(FM).val[0];
return focusMeasure;
}
// OpenCV port of 'LAPV' algorithm (Pech2000)
double varianceOfLaplacian(const cv::Mat& src)
{
cv::Mat lap;
cv::Laplacian(src, lap, CV_64F);
cv::Scalar mu, sigma;
cv::meanStdDev(lap, mu, sigma);
double focusMeasure = sigma.val[0]*sigma.val[0];
return focusMeasure;
}
// OpenCV port of 'TENG' algorithm (Krotkov86)
double tenengrad(const cv::Mat& src, int ksize)
{
cv::Mat Gx, Gy;
cv::Sobel(src, Gx, CV_64F, 1, 0, ksize);
cv::Sobel(src, Gy, CV_64F, 0, 1, ksize);
cv::Mat FM = Gx.mul(Gx) + Gy.mul(Gy);
double focusMeasure = cv::mean(FM).val[0];
return focusMeasure;
}
// OpenCV port of 'GLVN' algorithm (Santos97)
double normalizedGraylevelVariance(const cv::Mat& src)
{
cv::Scalar mu, sigma;
cv::meanStdDev(src, mu, sigma);
double focusMeasure = (sigma.val[0]*sigma.val[0]) / mu.val[0];
return focusMeasure;
}
Нет гарантий того, меры - лучший выбор для вашей проблемы, но если вы отследите документы, связанные с этими мерами, они могут дать вам больше информации. Надеюсь, вы найдете код полезным! Я знаю, что сделал.
Один из способов, который я использую в настоящее время, измеряет распространение ребер в изображении. Посмотрите на эту статью:
@ARTICLE{Marziliano04perceptualblur,
author = {Pina Marziliano and Frederic Dufaux and Stefan Winkler and Touradj Ebrahimi},
title = {Perceptual blur and ringing metrics: Application to JPEG2000,” Signal Process},
journal = {Image Commun},
year = {2004},
pages = {163--172} }
Обычно это за платой, но я видел несколько бесплатных копий. В основном, они определяют вертикальные края изображения, а затем измеряют ширину этих краев. Усреднение ширины дает окончательный результат оценки размытия для изображения. Более широкие края соответствуют размытым изображениям и наоборот.
Эта проблема относится к области оценки качества безреференсного изображения . Если вы посмотрите на Google Scholar, вы получите много полезных ссылок.
EDIT
Вот график оценок размытости, полученных для 5 изображений в сообщении nikie. Более высокие значения соответствуют большему размытию. Я использовал гауссовский фильтр с фиксированным размером 11x11 и менял стандартное отклонение (используя команду femfmememagick для получения размытых изображений).
[/g1]
Если вы сравниваете изображения разных размеров, не забудьте нормализовать ширину изображения, так как большие изображения будут иметь более широкие края.
Наконец, значительная проблема заключается в различии между художественным размытием и нежелательным размытием (вызванным фокусным промахом, сжатием, относительным движением объекта к камере), но это выходит за рамки простых подходов, подобных этому. Для примера художественного размытия взгляните на изображение Ленны: отражение Ленны в зеркале размыто, но ее лицо полностью сосредоточено. Это способствует более высокой оценке размытия для изображения Lenna.
Это то, что я делаю в Opencv для определения качества фокусировки в регионе:
Mat grad;
int scale = 1;
int delta = 0;
int ddepth = CV_8U;
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
/// Gradient X
Sobel(matFromSensor, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
/// Gradient Y
Sobel(matFromSensor, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y);
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
cv::Scalar mu, sigma;
cv::meanStdDev(grad, /* mean */ mu, /*stdev*/ sigma);
focusMeasure = mu.val[0] * mu.val[0];
Еще один очень простой способ оценить резкость изображения - использовать фильтр Laplace (или LoG) и просто выбрать максимальное значение. Использование надежной меры, такой как 99,9% квантиль, вероятно, лучше, если вы ожидаете шума (т. Е. Выбираете N-высокий контраст, а не самый высокий контраст). Если вы ожидаете изменения яркости изображения, вы также должны включить шаг предварительной обработки для нормализации яркости / контраст (например, выравнивание гистограммы).
Я реализовал предложение Саймона и этот в Mathematica и попробовал его на нескольких тестовых изображениях:
[/g0]
Первый тест размывает тестовые изображения с использованием гауссовского фильтра с различным размером ядра, затем вычисляет БПФ размытого изображения и принимает среднее значение на 90% самых высоких частот:
testFft[img_] := Table[
(
blurred = GaussianFilter[img, r];
fft = Fourier[ImageData[blurred]];
{w, h} = Dimensions[fft];
windowSize = Round[w/2.1];
Mean[Flatten[(Abs[
fft[[w/2 - windowSize ;; w/2 + windowSize,
h/2 - windowSize ;; h/2 + windowSize]]])]]
), {r, 0, 10, 0.5}]
Результат в логарифмическом графике:
[/g1]
5 строк представляют собой 5 тестовых изображений, ось X представляет собой гауссовский радиус фильтра. Графики уменьшаются, поэтому БПФ является хорошей мерой для резкости.
Это код для оценки вероятности «высшей точки»: он просто применяет LoG-фильтр и возвращает самый яркий пиксель в результате фильтра:
testLaplacian[img_] := Table[
(
blurred = GaussianFilter[img, r];
Max[Flatten[ImageData[LaplacianGaussianFilter[blurred, 1]]]];
), {r, 0, 10, 0.5}]
Результат в логарифмическом plot:
[/g2]
Распространение для не размытых изображений здесь немного лучше (2.5 против 3.3), главным образом потому, что этот метод использует только самые сильные контрастность изображения, тогда как БПФ является, по существу, средним по всему изображению. Функции также уменьшаются быстрее, поэтому может быть проще установить «размытый» порог.
Исходя из ответа Найка. Его простота для реализации метода на основе лапласа с помощью opencv:
short GetSharpness(char* data, unsigned int width, unsigned int height)
{
// assumes that your image is already in planner yuv or 8 bit greyscale
IplImage* in = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1);
IplImage* out = cvCreateImage(cvSize(width,height),IPL_DEPTH_16S,1);
memcpy(in->imageData,data,width*height);
// aperture size of 1 corresponds to the correct matrix
cvLaplace(in, out, 1);
short maxLap = -32767;
short* imgData = (short*)out->imageData;
for(int i =0;i<(out->imageSize/2);i++)
{
if(imgData[i] > maxLap) maxLap = imgData[i];
}
cvReleaseImage(&in);
cvReleaseImage(&out);
return maxLap;
}
Вернет короткое указание, указывающее на обнаруженную максимальную резкость, которая, основываясь на моих тестах на образцах реального мира, является довольно хорошим индикатором того, если камера находится в фокусе или нет. Неудивительно, что нормальные значения зависят от сцены, но много меньше, чем метод FFT, который должен иметь значение ложной положительной скорости, чтобы быть полезным в моем приложении.