jackjameshoward - 9 months ago 52

Python Question

What I'm trying to do in this example is wrap an image around a circle, like below.

To wrap the image I simply calculated the x,y coordinates using trig.

The problem is the calculated X and Y positions are rounded to make them integers. This causes the blank pixels in seen the wrapped image above. The x,y positions have to be an integer because they are positions in lists.

I've done this again in the code following but without any images to make things easier to see. All I've done is create two arrays with binary values, one array is black the other white, then wrapped one onto the other.

The output of the code is.

`import math as m`

from PIL import Image # only used for showing output as image

width = 254.0

height = 24.0

Ro = 40.0

img = [[1 for x in range(int(width))] for y in range(int(height))]

cir = [[0 for x in range(int(Ro * 2))] for y in range(int(Ro * 2))]

def shom_im(img): # for showing data as image

list_image = [item for sublist in img for item in sublist]

new_image = Image.new("1", (len(img[0]), len(img)))

new_image.putdata(list_image)

new_image.show()

increment = m.radians(360 / width)

rad = Ro - 0.5

for i, row in enumerate(img):

hyp = rad - i

for j, column in enumerate(row):

alpha = j * increment

x = m.cos(alpha) * hyp + rad

y = m.sin(alpha) * hyp + rad

# put value from original image to its position in new image

cir[int(round(y))][int(round(x))] = img[i][j]

shom_im(cir)

I later found out about the Midpoint Circle Algorithm but I had worse result with that

`from PIL import Image # only used for showing output as image`

width, height = 254, 24

ro = 40

img = [[(0, 0, 0, 1) for x in range(int(width))]

for y in range(int(height))]

cir = [[(0, 0, 0, 255) for x in range(int(ro * 2))] for y in range(int(ro * 2))]

def shom_im(img): # for showing data as image

list_image = [item for sublist in img for item in sublist]

new_image = Image.new("RGBA", (len(img[0]), len(img)))

new_image.putdata(list_image)

new_image.show()

def putpixel(x0, y0):

global cir

cir[y0][x0] = (255, 255, 255, 255)

def drawcircle(x0, y0, radius):

x = radius

y = 0

err = 0

while (x >= y):

putpixel(x0 + x, y0 + y)

putpixel(x0 + y, y0 + x)

putpixel(x0 - y, y0 + x)

putpixel(x0 - x, y0 + y)

putpixel(x0 - x, y0 - y)

putpixel(x0 - y, y0 - x)

putpixel(x0 + y, y0 - x)

putpixel(x0 + x, y0 - y)

y += 1

err += 1 + 2 * y

if (2 * (err - x) + 1 > 0):

x -= 1

err += 1 - 2 * x

for i, row in enumerate(img):

rad = ro - i

drawcircle(int(ro - 1), int(ro - 1), rad)

shom_im(cir)

Can anybody suggest a way to eliminate the blank pixels?

Answer

I think what you need is a noise filter. There are many implementations from which I think Gaussian filter would give a good result. You can find a list of filters here. If it gets blurred too much: * keep your first calculated image * calculate filtered image * copy fixed pixels from filtered image to first calculated image

Here is a crude average filter written by hand:

```
cir_R = int(Ro*2) # outer circle 2*r
inner_r = int(Ro - 0.5 - len(img)) # inner circle r
for i in range(1, cir_R-1):
for j in range(1, cir_R-1):
if cir[i][j] == 0: # missing pixel
dx = int(i-Ro)
dy = int(j-Ro)
pix_r2 = dx*dx + dy*dy # distance to center
if pix_r2 <= Ro*Ro and pix_r2 >= inner_r*inner_r:
cir[i][j] = (cir[i-1][j] + cir[i+1][j] + cir[i][j-1] +
cir[i][j+1])/4
shom_im(cir)
```

and the result:

This basically scans between two ranges checks for missing pixels and replaces them with average of 4 pixels adjacent to it. In this black white case it is all white.

Hope it helps!