I'm making a toy code to detect and fix scanline glitches on images.
I pick Lenna image from Wikipedia, and add horizontal scanline glitches, by multiplying the rows with random values between 0.9 and 1.1
To identify the horizontal scanline glitch, I calculate a moving average for each column, which should be close to the original value, and get the ratio between the moving average, and the glitchy value.
Because each row has the same glitch percentage, I collect the median ratio of each row, and multiply the glitchy row by that ratio to make the correction.
The result looks close to the original:
But when I calculate the difference between the corrected image and the original, I get color differences up to 255.
This doesn't makes sense. What I'm doing wrong?
import matplotlib.pyplot as plt
import cv2
import numpy as np
URL = "https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png"
def verticalMovingAvg(imgOrig, kernel_size=30):
'''Returns the vertical moving average of an image,
for each column, using a kernel of size kernel_size.
Also returns, for each row, the median of the
ratio moving average/image.'''
verticMeanImg=imgOrig*0
halfSize = kernel_size // 2
for col in range(imgOrig.shape[1]):
for row in range(imgOrig.shape[0]):
verticMeanImg[row, col] = np.mean(imgOrig[max(0,row-halfSize):min(imgOrig.shape[0],row+halfSize), col],axis=0)
return verticMeanImg, np.median(verticMeanImg/imgOrig, axis=1)
def downloadImage(URL):
'''Downloads the image on the URL, and convers to cv2 BGR format'''
from io import BytesIO
from PIL import Image as PIL_Image
import requests
response = requests.get(URL)
image = PIL_Image.open(BytesIO(response.content))
return cv2.cvtColor(np.array(image), cv2.COLOR_BGR2RGB)
def createScanlineGlithcedImage(img):
'''Returns an image with the size of the original image,
but with an horizontal scanline glith effect
on rows.'''
# Scanline deviation for each row
rowDeviation = np.random.uniform(.9, 1.1, (img.shape[0], 1))
#Multiplies each row by the deviation
imgGlitched = img*0
for row in range(img.shape[0]):
imgGlitched[row, :, :] = np.clip(img[row, :, :]*rowDeviation[row], 0, 255)
cv2.imshow('Glitched image', imgGlitched)
cv2.waitKey(10)
return imgGlitched, rowDeviation
img = downloadImage(URL)
cv2.imshow('Original image', img)
cv2.waitKey(10)
imgGlitched, rowDeviation = createScanlineGlithcedImage(img)
#Calculate correction
verticMobileAvgImage , medianCorrection= verticalMovingAvg(imgGlitched)
cv2.imshow('Vertical moving average', verticMobileAvgImage)
cv2.waitKey(10)
#Correct image
imgCorrected = imgGlitched*0
for row in range(imgGlitched.shape[0]):
imgCorrected[row, :, :] = np.clip(imgGlitched[row, :, :]*medianCorrection[row], 0, 255)
cv2.imshow("image corrected", imgCorrected)
cv2.waitKey(10)
#Plot error
# plt.plot(np.mean(imgCorrected-img, axis=1))
plt.imshow(imgCorrected-img)
plt.title("Error = image corrected-image original")
plt.show()
#animation of original and corrected
while True:
cv2.imshow("Image comparison", img)
cv2.waitKey(100)
cv2.imshow("Image comparison", imgCorrected)
cv2.waitKey(100)