# Image Processing: Flatten a 3D Ball

There are many descriptions of how to turn a 2D image into a 3D one, however I want to do the opposite, in particular to a ball. As an example, consider the following ball:

If only the (relatively) slow change in intensity due to the light could be removed, the ball would look 2D.

My first approach was to try get a low frequency version of the original, and divide through by that image. A simple way to do that is to blur the image. Here is a sample result using that approach:

This does the job of flattening the light, but there are some problems:

• There is a light 'halo' around sharp edges.
• Large flat patches (e.g. the black patches) lose their uniformity in the middle.
• The edges of the ball are affected by the background during the blurring (there's a dark ring around the ball, particularly noticeable at the bottom right corner).

I've tried mucking about with filters (e.g. bilinear) but haven't really found anything that works. I've also tried to use wavelets (a frequency based approach makes sense to me), but those approaches tended to distort the fine detail, which is very important.

Any ideas on how to do this are greatly appreciated!

• Can you give me another example of what you mean by 3D to 2D? Do you simply want a sort of flattened version of the image? As per your filtered example, do you want to ensure that uniform patches of intensity share the same intensity instead of that haloing effect? Jul 13, 2014 at 5:46
• Yeah I want to remove the changes due to slow variation, but without distorting the fine detail or the flat values. Kind of like a notch filter effect. I imagined the end result would look something like this, (except with the logo). Jul 13, 2014 at 15:15
• Cool. OK, I get it. Is the desired effect you want supposed to be in Black and White? This is a cool problem. It's like thresholding from colour! Jul 13, 2014 at 15:24
• The colour doesn't matter, I should've made the original image B&W (updated). Jul 13, 2014 at 15:27
• That's fine. Still wouldn't change how I would approach it. Give me a few moments. I'm gonna muck around with this Jul 13, 2014 at 15:29

## 2 Answers

My best attempt at this so far is kind of inspired by the difference of Gaussians. I'm putting it as an answer, even though I'm not totally happy with it.

Basically I made a blurred version of the image using two different Gaussian kernels. One captures the fine detail (small kernel) and the other captures the broad detail (large kernel). These two were then merged. This new blurred image is then subtracted from the original.

UPDATE: Made the process iterative, added contrast equalisation and changed blur divide to blur subtract.

output_image = get_input_image()

for i in xrange(4):
# Magic numbers
sigma_broad = 301
sigma_fine  = 5
merge_ratio = 0.5

# Get blur
broad_detail = cv2.GaussianBlur(output_image, (sigma_broad, sigma_broad), 0)
fine_detail  = cv2.GaussianBlur(output_image, (sigma_fine, sigma_fine), 0)
blurred = merge_ratio*broad_detail + (1-merge_ratio)*fine_detail

# Subtract blur from original (and correct for average drop in intensity)
output_image = (output_image + np.mean(blurred)) - blurred

# Contrast equalisation
clahe = cv2.createCLAHE(clipLimit=1.0, tileGridSize=(4,4))
output_image = clahe.apply(output_image.astype(np.uint8))


Result:

The reasons that I'm not totally satisfied with this result:

1. The information I want is altered. The objects in the ball (e.g. the dark patches) are disproportionally reduced.
2. There are some artefacts.
3. There are lots of magic numbers and parameters to fiddle with. Ideally the algorithm should be robust for a variety of balls.

ANOTHER UPDATE: I had a go at a Laplacian Pyramid filter, which I adapted from here. I got decent results, posting mainly for interest. This strategy allows for targeting frequency bands, but it's very fiddly.

• Sorry, I haven't forgotten about you. I didn't find a solution that is good enough to be posted. However, consider taking a look at homomorphic filtering. I used it to segment out characters on a license plate when the plate was subject to different shading. stackoverflow.com/questions/24731810/… Jul 16, 2014 at 21:07
• Thanks! I was actually just looking for a segmentation technique and this looks great! Jul 17, 2014 at 6:58

I tried a 2-D CA-CFAR approach the result and the code is as follows:

% image flattening
clear all; close all;
x = imread('DOX7f.png');
[r, c] = size(x);

N =10;
N2 = N/2;
R = r/N;
C = c/N;
y = zeros(r, c);
K = ones(N+1,N+1);
K(N2:N2+2, :) = 0;
K(:, N2:N2+2) = 0;
K = K/sum(K(:));
y2 = filter2(K, x);
y2 = x > 0.98*y2;

figure(1);
imshow(y2);


The 2-D kernel

The output

Is it what you were looking for?

• Thanks, I had never encountered this technique before. It seems quite fragile to the selection of the constant in the last operation (0.98 in your example) though. Ideally I'd like this to work on multiple balls, without having to fiddle with parameters like that for each one. It also has some artefacts (the thick dark ring around the ball for example), and hasn't preserved the flat (black) patches. Thanks for giving me something new to play around with though! Jul 15, 2014 at 9:49
• @PokeyMcPokerson Basically the idea was to find a starting point method with variable thresholding. You are right, there are many artifacts and it is very very sensitive to the scaling factor. Besides I also tried histogram equalization at local (10x10 to 100x100 block) and global scale. I tried thresholding based on mean again local and global. Din seem to work that well. Jul 15, 2014 at 9:56