pátek 22. března 2019

How to fix backlight bleed

Sometimes a laptop display gets damaged by pressure or water. And the damage manifests itself by the presence of bright spots:

The best way how to get rid of the white speckles is to change the display. But that can cost like a new laptop. A fast and free solution is to use a dark theme thru the system - the bright spots are not so irritating on the dark background as they are on bright background. But if we are determined to stick with the light theme, we can overlay the screen with an image, which is dark where the speckles are and otherwise is transparent. Note that this solution is not perfect - when you see bright spots on the display, it is because the backlight layer got damaged. And because there is some nonzero space between the backlight and the pixels, we can get a perfect alignment only for a single observation point - when we move our head a bit, the overlay image gets slightly misaligned and the edges of the speckles will be visible. Furthermore, it took me a few hours to get acceptable results with this approach.

Walkthrough for using the overlay method:
    1) Get an application that can permanently overlay an image over the screen. On MacOS, I used Uberlayer.
    2) Make a good photo of the display with completely white background. The camera should be roughly at the position, from which you commonly look at the screen. Also, we want to take a longer exposition (e.g.: 1 second) in order to avoid capturing the display refresh deformations (they look like a moire pattern on my display). Hence, a stative can be handy. Finally, it can be better to take a photo in a darkened room in order to avoid capturing reflections on the display.
    3) Convert the photo to shades of shade.
    4) Write down the position of the bright spots on the photo in pixels.
    5) Write down the position of the bright spots on your display in pixels. I used Ruler.
    6) Align the photo to the screen with a combination of RANSAC and projective transformation.
    7) Homogenize the illumination of the photo.
    8) Invert the color of the image - bright spots will become dark spots.
    9) Set the transparency.
  10) Use the generated image as the screen overlay.

The script in Matlab:
% Load data
original = rgb2gray(imread('photo.tif'));



% Location of spots on the photo (as read from: imshow(original))
% From: left x top.
photo = [
    556     1125    % the brightest speckel
    101     961     % the single speckel on the left
    61      1578    % the bottom left single pixel
    2422    1161    % right: the top bright spot
    2465    1216    % right: the lowest bright spot on right
    1065    698     % middle: the brightest speckel (north west) 
    15      31      % corners...
    2545    1637
    22      1630
    2548    67
];

% Location of bright points on the display
% Averaged from 2 measures
screen = [
    302.5   611     % the brightest speckel
    47      523     % the single speckel on the left
    23      870     % the bottom left single pixel
    1367.5  627     % right: the top bright spot
    1393.5  658.5   % right: the lowest bright spot on right
    589     368     % middle: the brightest speckel (north west)
    1       1       % corners...
    1440    900
    1       900
    1440    1
];

% Visualization
figure('Name', 'Photo')
imshow(original);
hold on
plot(photo(:,1), photo(:,2), 'or')

% Map photo to screen coordinates
rng(2001); % RANSAC is stochastic (it may exclude outliers) -> set seed
[tform, inlierpoints1, inlierpoints2] = estimateGeometricTransform(photo, screen, 'projective', 'MaxDistance', 3);

% Transform the photo
outputView = imref2d(size(original));
image = imwarp(original, tform, 'OutputView', outputView, 'FillValues', 255);

% Crop the image to the size of the screen
image = image(1:900, 1:1440);

% Plot the aligned photo
figure('Name', 'Photo after transformation')
imshow(image)
hold on
plot(screen(:,1), screen(:,2), 'ob')

%% Illumination homogenization
% First, we remove the white speckles. See:
%   https://www.mathworks.com/help/images/correcting-nonuniform-illumination.html
se = strel('disk', 25);
background = imopen(image, se);

% Gaussian smoothing creates nicely smooth transitions (at least with doubles)
smoothed = imgaussfilt(double(background), 25);

% Subtract background illumination from the image to get the foreground
foreground = double(image) - smoothed;

% Remove too dark pixels (essentially the leaking border)
threshold = median(foreground(:)) + std(foreground(:));
borderless = max(threshold, foreground);
imagesc(borderless)

%% Invert the colors
result = uint8(255-(borderless-threshold));
imshow(result)

%% Set transparency
black = uint8(ones(900, 1440));

maximum = max(borderless(:));
minimum = min(borderless(:));
alpha = (borderless-minimum)/(maximum-minimum);

%% Store the image
imwrite(black, 'overlay.png', 'alpha', alpha)