Histogram Equalization is one of the fundamental tools in the image processing toolkit. It’s a technique for adjusting the pixel values in an image to enhance the contrast by making those intensities more equal across the board. Typically, the histogram of an image will have something close to a _normal_ distribution, but equalization aims for a _uniform_ distribution. In this article, we’re going to program a histogram equalizer in python from scratch. If you want to see the full code, I’ve included a link to a Jupyter notebook at the bottom of this article. Now, if you’re ready, let’s dive in!\n\nBefore anything, we have to do some setup. Let’s import the libraries we’ll be using throughout the program, load in the image, and display it:\n\n!(https://hackernoon.com/hn-images/1*3LcQlcqMdVsCfJybcZKwPg.png)\n\n!(https://hackernoon.com/hn-images/1*H_ekCDVcynVnNzdTk_fENA.png)\n\nFor the purposes of this tutorial, we’re using a grayscale image since each pixel in a grayscale image represents only one value — the _intensity_. I think this makes the math easier to reason about since we only have to care about one value. For comparison, in an RGB color image, each pixel contains three values (Red/Green/Blue). Due to how we’re reading in and processing the image, you can still run a color image through this program — and I encourage you to so you can see what kind of output you’d get!\n\nThe image we’ll be using is a washed-out x-ray. We can pretend that we’re radiologists that want to equalize the x-ray to better see some of the details.\n\nIn order to process the image, we have to first read it in as an array. However, numpy will automatically return a multi-dimensional array, so we flatten it to a one-dimensional array:\n\n!(https://hackernoon.com/hn-images/1*3LcQlcqMdVsCfJybcZKwPg.png)\n\n!(https://hackernoon.com/hn-images/1*OfpJjC8EOZMVH89fDDx82A.png)\n\nIn the flattened array, we have an intensity value for every pixel. The values will range from 0 (_black_) to 255 (_white_). Everything in between can be considered a shade of gray. As you can see from the diagram above, we have a spike of values near zero and not many values over 200.\n\nWe can now take our one-dimensional array and compute the histogram for the image based on the frequency of similar intensity values. There are pre-existing functions that will do this for you, but we’re making this from scratch, so let’s write our own!\n\n⚠️ _Keep in mind that for production environments, you would want to use pre-existing functions since they’re better optimized, and can handle more use cases._\n\nThe mathematical formula from which we’ll base our solution is:\n\n!(https://hackernoon.com/hn-images/1*1vgTqBckFxcJ_njZujsgJw.png)\n\nNow we have our histogram, and we can take the next step towards equalization by computing the _cumulative sum_ of the histogram. The cumulative sum is exactly as it sounds — the sum of all values in the histogram up to that point, taking into account all previous values. Just as above, there are functions that exist to compute this for you, but let’s write our own:\n\n!(https://hackernoon.com/hn-images/1*i47V21rtuaN5Jor7XDhMeA.png)\n\n!(https://hackernoon.com/hn-images/1*sAz6oyPNutuKbScRhpvStw.png)\n\nWe’re making progress! We now have the cumulative sum, but as you can see, the values are huge (> 6,000,000). We’re going to be matching these values to our original image in the final step, so we have to normalize them to conform to a range of 0–255. Here’s one last formula for us to code up:\n\n!(https://hackernoon.com/hn-images/1*7rIAl9KHsWm02N0aXfqo_Q.png)\n\n!(https://hackernoon.com/hn-images/1*i47V21rtuaN5Jor7XDhMeA.png)\n\n!(https://hackernoon.com/hn-images/1*eI5mAzXbWmcUx-OLj0eWWQ.png)\n\nThat’s better — our values are now normalized between 0-255. Now, for the grand finale. We can now use the normalized cumulative sum to modify the intensity values of our original image. The code to do this can look a bit confusing if you’ve never used numpy before. In fact, it’s anti-climactically simple.\n\nWe’ll take all of the values from the `flat` array and use it as the index to look up related value in the `cs` array. The result becomes the new intensity value which will be stored in `img_new` for that particular pixel.\n\nAs a final step, we reshape the array to match the original image so we can render the result as an image.\n\n!(https://hackernoon.com/hn-images/1*i47V21rtuaN5Jor7XDhMeA.png)\n\n!(https://hackernoon.com/hn-images/1*BQFBvFQ8MAo2A8qC8NDd0g.png)\n\nAnd there we have it — the original image has been equalized. We’re practically radiologists now! Notice the difference in contrast throughout the whole image. The most important thing to remember about histogram equalization is that it adjusts the intensities at a _global_ level, taking into account all pixels. That process works well for images like the one above but may perform poorly on other images.\n\nFor example, take the image below — it was transformed using the exact same algorithm, however, you can see that it didn’t enhance the photo as much as it _utterly destroyed it_:\n\n!(https://hackernoon.com/hn-images/1*dhmQZTHT8djW1yaDVBjS7g.png)\n\nHistogram equalization isn’t always the perfect tool for the job. But, there are other methods you can use that take neighboring pixels into consideration instead of using the entire image. Stay tuned for the next article where we’ll walk through a more localized equalization algorithm.\n\nThe full source code (as a Jupyter notebook) for this article can be found here:\n\n[**torywalker/histogram-equalizer** \n_A simple histogram equalization implementation. Contribute to torywalker/histogram-equalizer development by creating an…_github.com](https://github.com/torywalker/histogram-equalizer/blob/master/HistogramEqualization.ipynb "https://github.com/torywalker/histogram-equalizer/blob/master/HistogramEqualization.ipynb")(https://github.com/torywalker/histogram-equalizer/blob/master/HistogramEqualization.ipynb)\n\n👏 If you found this article helpful and would like to see more, please let me know by leaving some claps! 🔗 Follow for more articles like this!