Vision Quest

HoG - Histogram of Gradients

UFO:Detector Test
FAIL

Desert Moon - Sidereal Galaxy Ways
image courtesy of the late
Eddie Takosori

This document has not been classified by the CIDC
nor had it been documented would we be at liberty to disclose said rating

I'm I am the curator Eddie's life work, this photo comes from his personal effects. Make of it what you will.


First an image of an embassy.
Something neither the Arturians
(I think that's how it's spelled)
nor the CIDC
(once again, I'm pretty sure that's the correct acronym for the CIDC)
ever want you to see.

So, like, you didn't see it here first (if you know what I mean).


HoG - Histogram of Gradients - Test Image - Desert Moon Sidereal Galaxy Ways - UFO Detector Fail

C is the Cell size. Since HoG measures a gradient, the smallest meaningful cell is (2,2).

I found no effect from changes in B (the block size) for any test run. So variance in B is omitted throughout.

For C=(2,2), there was no difference due to number of slots in the histogram (h=1,h=2,h=4,h=8 omitted).

HoG - Base Test Run

C varies per column
H varies per row

HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image

Above: Two Histograms per Cell

HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image

Above: Four Histograms per Cell

HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image

Above: Eight Histograms per Cell

HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image

Above: Sixteen Histograms per Cell

HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image

Above: Thirty Two Histograms per Cell

Same Thing - Larger Cells

HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image
c=500 (the column on the far right) is an interesting test condition as one cell takes up the entire image.

HoG - Cell Decomposition

HoG - Test Image

Above: One Image

Below: Sixteen Sub-Images

HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image
HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image
HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image
HoG - Test Image HoG - Test Image HoG - Test Image HoG - Test Image

Color Test

This should be self-explainatory. But if not, in the following, I plug the histogram return values in for the standard rgb color values. Thereby, replacing the funky default star graphics of from skimage.feature import hog with color.

HoG - Test Image

RGB images use three color layers.
If h=3, HoG kicks back three histogram values.
Rocket Science, this is not.

HoG - Test Image HoG - Test Image HoG - Test Image

For reference: these are the raw histogram values
Presented counterclockwise, from left-top
columns are [red  green  blue]

x000-y000 [ 0.46650601  0.30661453  0.18926898]
x250-y000 [ 0.31422072  0.4707383   0.20310213]
x250-y250 [ 0.25183926  0.58050045  0.15758351]
x000-y250 [ 0.30955919  0.43543831  0.15302716]

The brightest squares match up with the highest values, so it looks right to me.

HoG - Test Image

This is the combined overlay.
But at this scale, it's not very interesting, so...

HoG - Test Image

which when plugged in for color yields

HoG - Test Image

which still isn't very interesting, but now that the idea is clear, all we have to do is reduce the cell size to something a little more refined (i.e. a little less granular); and when we plug the histograms in for color, we get:

HoG - Test Image with Color HoG - Test Image with Color

The image on the right has been 'stretched' (normalized) to fill the full color gradient from 0.00 to 1.00, but as there's no real difference, I won't bother with that anymore.

The cell size on the above is 5.
Below, it's 2.

HoG - Test Image

Base colorized image, h=2.

HoG - Test Image with Color HoG - Test Image with Color

Images passed through a low pass filter.
If color value below 0.25 on left (hogValue < 0.25),
below 0.33 or right (hogValue < 0.33)

Not stretched, so maybe I there was a reason I included a stretching function...

HoG - Test Image with Color HoG - Test Image with Color

Above are the same images stretched (color expanded to fill the full gradient).

There is a lot more action (noticable) action in the air in these images, which is as one might expect, what with the humming of the Van Der Wahl drives and all.

HoG - Test Image with Color HoG - Test Image with Color HoG - Test Image with Color

The above are after passing the results through a high pass filter.
Greater than 0.50 (hogValue > 0.50)
Greater than 0.75 (hogValue > 0.75)
Greater than 0.90 (hogValue > 0.90)
from left to right.


And I do believe I will have some pretty gif's of this at the bottom of the page, but first some code. You do like code, don't you?

HoG (Histogram of Gradients) - Python Code


First, the stretch function. Nothing fancy.
def stretch(a):
    '''normalizes the values in an array
    from 0.0 to 1.0
    '''
    a = a - numpy.min(a)
    if numpy.max(a) != 0.00:
        a = a / numpy.max(a)
    return a

Everything shown on this page (except for the animated gif's, to follow below) can be derived from judicious use of the following function.

import numpy
from skimage import io
from skimage.feature import hog

def hogFdTest(img, c=250, nH=3,
               tL=0.00, tH=1.00,
                expand=False):
    '''
        a function to play with
            from skimage.feature import hog
             
        img = a greyscale image array
            io.imread(sN, as_grey=True)
            
        c = cell size = (c,c)
            must be an integer
            2 is the lowest that will work
            up to picture size
            
        nH = numberHistograms
            3 works well if splitting
                to picture bands r,g,b
            as goes higher, grinds to a halt
                takes a lot of time
            as written nH must be 3 or greater
        
        tL and tH together form a band pass
            tL = lowest number to pass
            tH = higherst number to pass
            tL=0.00, tH=1.00
                passes everything
        
        expand if true
            referred to as 'stretch' in text
            renormalizes gradients 
            to range 0.00 - 1.00
            regardless of the band passed
        
        returns
            iO = a numpy image array (w,h,4)
            hV = hog values
                a['name'] = holding name
                a['hog'] = values
                a['xS'] = xStart
                a['xE'] = xEnd
                a['yS'] = yStart
                a['yE'] = yEnd
        
    '''
    print "hogFdTest Starting"
    
    nH = int(nH)
    c = int(c)

    #creating the r,g,b,a holding arrays
    w, h = img.shape
    r = numpy.ndarray((w,h), float)
    g = numpy.ndarray((w,h), float)
    b = numpy.ndarray((w,h), float)
    a = numpy.ones_like(g, float)
    z = numpy.zeros_like(a, float)    
    
    
    #splits image into chuncks
    #based on c=cellSize
    sC = [(x,y) for x in range(0,w,c)
                for y in range(0,h,c)]

    #holding object for fd arrays
    hV=[]

    for x,y in sC:
        
        s = img[x:(x+c),y:(y+c)]
        
        #fd is an array with len(fd)=nH
        fd = hog(s, orientations=nH,
                  pixels_per_cell=(c,c),
                    cells_per_block=(1, 1),
                     visualise=False)   
    
        #creation of return value object
        #fill it with values
        #append to the return array hV
        t = {}
        t['name'] ="xy%s%s" % (nFL(x),nFL(y))
        t['hog'] = fd
        t['xS'] = x
        t['xE'] = x + c
        t['yS'] = y
        t['yE'] = y + c
        hV.append(t)
    
        #first three 
        r[x:(x+c),y:(y+c)] = fd[0]
        g[x:(x+c),y:(y+c)] = fd[1]
        b[x:(x+c),y:(y+c)] = fd[2]
    
    #high pass, passes higher than tL
    r = numpy.where((r>=tL), r, z)
    g = numpy.where((g>=tL), g, z)
    b = numpy.where((b>=tL), b, z)
    
    #low pass, passes lower than tH
    r = numpy.where((r<=tH), r, z)
    g = numpy.where((g<=tH), g, z)
    b = numpy.where((b<=tH), b, z)
    
    #stretched the passed band
    #to fill the full range 0.00 - 1.00
    if expand:
        r = stretch(r)
        g = stretch(g)
        b = stretch(b)

    #assembling 4 (w,h) arrays into one
    #(w,h,4) array RGBA
    iO = numpy.dstack((r,g,b,a))
                      
    sN = "ufo_%s_%f-%f.png" % (nFL(c), tL, tH)
    print "hogFdTest saving %s" % sN
    io.imsave(sN, iO)  
    
    #We'll play with hV in a moment
    return iO,hV  
'''
#Example test code for hogFdTest
#Bandpass filter
for r in range(0,100,10):
    r = r/100.00
    hogFdTest(io.imread(sN, as_grey=True),
              c=2, nH=3, tL=(r), tH=(r+0.10),
              expand=True)
'''

The above includes a hV return value, which the code below plays with a little (but just a little).

def analyzeHOGValues(img):

    d, h500 = hogFdTest(img, c=500)
    d, h250 = hogFdTest(img, c=250)
    d, h125 = hogFdTest(img, c=125)

    print "Sum of Gradients Full Image"
    print "h500 :  " + str(sum(item['hog']
                    for item in h500))
    print "h250 :  " + str(sum(item['hog']
              for item in h250)/len(h250))
    print "h125 :  " + str(sum(item['hog']
              for item in h125)/len(h125))


    print "250 vs 125 Corner Test"
    c = [item['hog'] for item in h250 if
               (item['xE'] <= 250) and
               (item['yE'] <= 250)]
    print "h250 :  " + str(sum(c)/len(c))
    c = [item['hog'] for item in h125 if
              (item['xE'] <= 250) and
              (item['yE'] <= 250)]
    print "h125 :  " + str(sum(c)/len(c))

sN = "./butterfly/png/UFO-500x500.jpg"
img = io.imread(sN, as_grey=True)

The output for the above being:

Sum of Gradients Full Image
h500 :  [ 0.32074886  0.47799351  0.1798315 ]
h250 :  [ 0.33553129  0.4483229   0.17574545]
h125 :  [ 0.26137455  0.42913492  0.12500847]

250 vs 125 Corner Test
h250 :  [ 0.46650601  0.30661453  0.18926898]
h125 :  [ 0.29768439  0.32754795  0.09223276]


Um?

I do believe I read somewhere that one of the reasons HoG got so much play was due to it's resistance to changes in scale.
So, much for that notion.
The above clearly demonstrates either:
A: My utter lack of understanding as to what the HoG gradient values mean, or
B: There is a wide variance based on scale

Do to reasons of Super-Ego-Id Overwhelming-Superiority of My Nature, I choose to believe it is the latter.

HoG Tied - Wrapping It Up

And that's about it. A few more pretty pictures, maybe a witty commentary or two, and I do believe that will be all.

HoG - Band Pass - Color Gradient Test Images - of the Arturian Embassy on some Sidereal Galaxy Desert Moon (it go blink-blink-blink) HoG - Band Pass - Color Gradient Test Images - of the Arturian Embassy on some Sidereal Galaxy Desert Moon (it go blink-blink-blink)
HoG - Band Pass - Color Gradient Test Images - of the Arturian Embassy on some Sidereal Galaxy Desert Moon (it go blink-blink-blink) HoG - Band Pass - Color Gradient Test Images - of the Arturian Embassy on some Sidereal Galaxy Desert Moon (it go blink-blink-blink)

0.10 Bandpass on the Left : 0.25 Bandpass on the right

Split by band in the top row above.
Additive (increasing window size from 0.00-0.10 to 0.00-1.00) underneath.


And then, below, we have the same thing, only cell size is 2 (bandpass top row, additive below).

HoG - Band Pass - Color Gradient Test Images - of the Arturian Embassy on some Sidereal Galaxy Desert Moon (it go blink-blink-blink)
HoG - Band Pass - Color Gradient Test Images - of the Arturian Embassy on some Sidereal Galaxy Desert Moon (it go blink-blink-blink)

And there you have it. It being, of course, the yellow tri-wing aerial assault vehicles that can be seen hovering in the background once one dials the 'scanner' in to the right frequency.

Obviously, it's all hush-hush, need to know, probably some diplo-corps mission debriefing thingy. Anyway, we all know who flies around in those 'tri's', so no sense belaboring the point.


The news will hit the Ethers soon enough.
Just remember, you heard it here first.
Or on second thought, I haven't said a thing.

Haven't said enough.
Already said to much.

Or if you want to believe I mess around with these things because I am of fan of graphic art, well, if that's the case, darned if I know what I'm going to do with this new tech. Maybe I've just been playing with the wrong images...


HoG Color Gradient
Top Secret
CIDC Demo Page
(aka more pretty pictures like these last two)



Back To
Vision Quest


Or now that we're done with that problem,
perhaps you'd like to rest your weary head and check out:

www.paufler.net/takosori
I'm the curator of his life work, you know.
OK. True enough. It's only because I'm his biggest fan.
Eh, perhaps only fan...



Or if you're a workaholic like me,
and are interested in more Python tricks?
Brett's Python Cheat Sheet

Brett@Paufler.net

Terms of Service © Copyright 2014 Brett Paufler