Histogram Equalization

It’s still not possible for us to know what image[i,j] contains, but FWIW note that 1 is a literal that automatically gets parsed as Int (Int64 on most systems):

julia> typeof(1)
Int64

I don’t understand why you think you need the UInt8() conversion here, but adding 1 to the result of UInt8() makes this conversion superfluous anyway due to type promotion that happens when adding a UInt8 and an Int:

julia> UInt8(255)
0xff

julia> UInt8(255) + 1
256

julia> typeof(UInt8(255) + 1)
Int64
1 Like

Again, this is not a good idea, since you will get an error unless image[i,j] * 255 is exactly a whole number. Therefore, you should use round or trunc instead.

1 Like

I understand now how it works. Thanks!

if you see the code, I’m didn’t add “+1” to

frequency[UInt8(image[i,j] * 255) ] += 1

which doesn’t make sense to get a histogram. so i updated that line to

frequency[UInt8(image[i,j] * 255) +1 ] += 1  #this works

The explanation for using UInt8 and multiplying by 255 is explained my tutor as follow,

You need to cast like this in order to use the image values for access. The internal representation uses Normed{UInt8, 8}, since this corresponds directly to the underlying data representation (UInt8), but also behaves like a floating point number, so you can do useful calculations on the images without converting between representations.

and the image is Gray image

i couldn’t upload the image as it’s in .tif file.

But you’re doing it here:

UInt8(image[i,j] * 255) +1 will not be an UInt8, because an UInt8 plus an Int64 is an Int64, and 1 is an Int64, look:

julia> typeof(UInt8(5) + 1)
Int64

Since you don’t provide any example image data, it’s difficult to say whether what your tutor is saying is correct, but it looks strange to me. As far as I understand image[i,j] * 255 will be a Float32, and in that case there’s no obvious need to use UInt8, but I guess no harm, either. But I am very skeptical of using UInt8() instead of round(UInt8, ) or trunc(UInt8, ).

Okay to reduce the confusion I went ahead an installed TestImages. Here’s what’s happening (I think):

julia> using Images, TestImages

julia> image = testimage("cameraman.tif");

julia> typeof(image)
Array{Gray{Normed{UInt8,8}},2}

So image is an array of Gray{Normed{UInt8,8}} elements:

julia> image[1,1]
Gray{N0f8}(0.612)

If you multiply those by an Int, as you do, you end up with:

julia> image[1,1]*255
Gray{Float32}(156.0f0)

that doesn’t work for indexing, you need an integer. You converted this back to UInt8:

julia> UInt8(image[1,1]*255)
0x9c

but then you’re directly adding a 1, which as we said is just a literal that gets parsed as an Int64, and adding that to your UInt8 just gives you a regular Int:

julia> UInt8(image[1,1]*255)+1
157

So this is essentially the same as doing:

julia> Int(image[1,1]*255)+1
157

Thanks for looking that up.

Question is, is

guaranteed to always be a whole number?

I don’t know enough about how images are represented, but there might be something about the Gray{N0f8} that means it holds discrete levels of 255 shades of gray which will always be an integer between 1 and 255 when multiplied by 255?

@DNF I noticed once of your reply saying, where the below code is initialized.

out[UInt8([i,j] * 255)]

Dumb me, I didn’t do that. Now I initialize with,

out = zeros(Uint8, sizeof(image))

As I already initialized out with UInt8, I don’t need to do the conversion again in the code. So now I can change the line to

out[i,j] = cdf[image[i,j] + 1]

And, I have attached an .png file and the code to show the working of histogram for the line, frequency[UInt8(image[i,j] * 255)+1 ] += 1

julia> function myHis(image)
       m, n = size(image)
       frequency = zeros(256)
           for i in 1:m, j in 1:n
               frequency[UInt8(image[i,j] * 255)+1 ] += 1    
           end
    
        return frequency ./ sizeof(image)
        end

obstA

between 0 and 255.
0 represents black and 255 represents white