Skip to content

Instantly share code, notes, and snippets.

@tlang0
Last active December 20, 2015 03:58
Show Gist options
  • Save tlang0/6066999 to your computer and use it in GitHub Desktop.
Save tlang0/6066999 to your computer and use it in GitHub Desktop.
A simple and inefficient histogram equalization program in Go1
/*
histeq - Histogram Equalizer
Copyright (C) 2012 wst <[email protected]>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package main
import (
"fmt"
"os"
"image"
"image/jpeg"
"image/color"
)
type Histogram []uint32
type Cumsum []uint32
func getGrayValueAt(img image.Image, x, y int) color.Gray {
// r, g, b will be equal for grayscale images => ignore other channels
v, _, _, _ := img.At(x, y).RGBA()
// convert/reduce from 16 bit to 8 bit and return
return color.Gray{uint8(v / 0x101)}
}
// equalize the histogram of an image and return the new image
func equalizeHist(img image.Image, cumsum Cumsum) image.Image {
cumMax := cumsum[255]
b := img.Bounds()
newImage := image.NewRGBA(image.Rect(b.Min.X, b.Min.Y, b.Max.X, b.Max.Y))
for i := b.Min.X; i < b.Max.X; i++ {
for j := b.Min.X; j < b.Max.Y; j++ {
// get pixel value
c := getGrayValueAt(img, i, j)
// equalize
c.Y = uint8((float64(cumsum[c.Y]) / float64(cumMax)) * 255)
newImage.Set(i, j, c)
}
}
return newImage
}
// returns an array of length 256 with the cumulated sums of the histogram
func makeCumsum(hist Histogram) Cumsum {
cumsum := make([]uint32, 256)
for i, v := range hist {
if i == 0 {
cumsum[0] = v
} else {
cumsum[i] = cumsum[i-1] + v
}
}
return cumsum
}
// return an array of length 256 containing the value counts
func makeHistogram(img image.Image) Histogram {
b := img.Bounds()
hist := make([]uint32, 256)
for i := b.Min.X; i < b.Max.X; i++ {
for j := b.Min.X; j < b.Max.Y; j++ {
// get pixel value
c := getGrayValueAt(img, i, j)
// add to histogram
hist[c.Y]++
}
}
return hist
}
func main() {
if len(os.Args) != 2 {
fmt.Printf("%s: Missing input file\n", os.Args[0])
os.Exit(1)
}
// open input file
inputFilename := os.Args[1]
fileIn, err := os.Open(inputFilename)
if err != nil {
panic("Could not open input file!")
}
// open output file
outputFilename := inputFilename + "_eq.jpg"
fileOut, err := os.Create(outputFilename)
if err != nil {
panic("Could not create/open output file!")
}
// decode
img, err := jpeg.Decode(fileIn)
if err != nil {
panic("Could not decode file as JPEG!")
}
// process the image
hist := makeHistogram(img)
cumsum := makeCumsum(hist)
newImg := equalizeHist(img, cumsum)
options := new(jpeg.Options)
options.Quality = 100
jpeg.Encode(fileOut, newImg, options)
// close files
fileIn.Close()
fileOut.Close()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment