Как я могу порочить это размытое изображение, чтобы сделать цифры как можно более ясными?
В предыдущем посте, я попытался адаптивно порождать размытое изображение (слева), что привело к искаженным и отключенным цифрам (справа):
С тех пор я попытался использовать морфологическую операцию закрытия, описанную в этом сообщении, чтобы сделать яркость изображения равномерным:
Если я адаптивно порою это изображение, я не получаю значительно лучших результатов. Однако, поскольку яркость примерно одинаковая, я могу теперь использовать обычный порог:
Это намного лучше, чем раньше, но у меня две проблемы:
- Мне пришлось вручную выбрать пороговое значение. Хотя операция закрытия приводит к равномерной яркости, уровень яркости может отличаться для других изображений.
- Различные части изображения будут лучше с небольшими изменениями порогового уровня. Например, 9 и 7 в верхнем левом углу частично выцветают и должны иметь более низкий порог, в то время как некоторые из 6s слились в 8s и должны иметь более высокий порог.
Я думал, что возврат к адаптивному порогу, но с очень большим размером блока (1/9 изображения), решит обе проблемы. Вместо этого я получаю странный "эффект ореола", где центр изображения намного ярче, но края примерно такие же, как у обычного изображения:
Изменить: remi предложил морфологически открывать пороговое изображение в правом верхнем углу этой публикации. Это не работает слишком хорошо. Используя эллиптические ядра, только 3x3 достаточно мала, чтобы полностью не стереть изображение, и даже тогда в цифрах имеются значительные разрывы:
Edit2: mmgp предложил, используя фильтр Винера, чтобы удалить размытие. Я адаптировал этот код для фильтрации Винера в OpenCV в OpenCV4Android, но он делает изображение еще более размытым! Здесь изображение перед (слева) и после фильтрации с моим кодом и ядром 5x5:
Вот мой адаптированный код, который фильтрует на месте:
private void wiener(Mat input, int nRows, int nCols) { // I tried nRows=5 and nCols=5
Mat localMean = new Mat(input.rows(), input.cols(), input.type());
Mat temp = new Mat(input.rows(), input.cols(), input.type());
Mat temp2 = new Mat(input.rows(), input.cols(), input.type());
// Create the kernel for convolution: a constant matrix with nRows rows
// and nCols cols, normalized so that the sum of the pixels is 1.
Mat kernel = new Mat(nRows, nCols, CvType.CV_32F, new Scalar(1.0 / (double) (nRows * nCols)));
// Get the local mean of the input. localMean = convolution(input, kernel)
Imgproc.filter2D(input, localMean, -1, kernel, new Point(nCols/2, nRows/2), 0);
// Get the local variance of the input. localVariance = convolution(input^2, kernel) - localMean^2
Core.multiply(input, input, temp); // temp = input^2
Imgproc.filter2D(temp, temp, -1, kernel, new Point(nCols/2, nRows/2), 0); // temp = convolution(input^2, kernel)
Core.multiply(localMean, localMean, temp2); //temp2 = localMean^2
Core.subtract(temp, temp2, temp); // temp = localVariance = convolution(input^2, kernel) - localMean^2
// Estimate the noise as mean(localVariance)
Scalar noise = Core.mean(temp);
// Compute the result. result = localMean + max(0, localVariance - noise) / max(localVariance, noise) * (input - localMean)
Core.max(temp, noise, temp2); // temp2 = max(localVariance, noise)
Core.subtract(temp, noise, temp); // temp = localVariance - noise
Core.max(temp, new Scalar(0), temp); // temp = max(0, localVariance - noise)
Core.divide(temp, temp2, temp); // temp = max(0, localVar-noise) / max(localVariance, noise)
Core.subtract(input, localMean, input); // input = input - localMean
Core.multiply(temp, input, input); // input = max(0, localVariance - noise) / max(localVariance, noise) * (input - localMean)
Core.add(input, localMean, input); // input = localMean + max(0, localVariance - noise) / max(localVariance, noise) * (input - localMean)
}