Calculating Adaptive Threshold in OpenCV
Tags: ai, computervision
Published: 2024-07-12 02:59:27

[Read my article on Thresholding and Binary Images for a better background](https://dev.to/catheryn/binary-images-image-thresholding-282)

Adaptive thresholding is a technique used to convert a grayscale image to a binary image (black and white). The threshold value is calculated for smaller regions (blocks) of the image rather than using a single global threshold value for the entire image.

We can perfom adaptive thresholding in OpenCV using this method:

```
img = cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst])
```
An explanation of the arguments:

- **src:** The image to be worked on.
- **maxValue:** The maximum value to use with the thresholding type.
- **adaptiveMethod:** The adaptive thresholding method to use. We have the [Adaptive_THRESH_MEAN_C and ADAPTIVE_THRESH_GAUSSIAN_C](https://docs.opencv.org/4.x/d7/d1b/group__imgproc__misc.html).
- **thresholdType:** The type of thresholding to apply. In this article we use the THRESH_BINARY. Read more about the [different threshold types](https://docs.opencv.org/4.x/d7/d1b/group__imgproc__misc.html#gaa9e58d2860d4afa658ef70a9b1115576) 
- **blockSize:** The size of the block to calculate the threshold for.
- **C:** A constant subtracted from the calculated mean. This constant fine-tunes the thresholding.

## The Mean Calculation

First, we read the image:

```
# Read the original image.
img = cv2.imread('test_image.png', cv2.IMREAD_GRAYSCALE)

```
Let us assume the image translates to these numbers: 

```
[[218 217 216 221 220 220]
 [211 210 210 215 216 216]
 [212 211 211 214 216 216]
 [139 138 137 103 105 105]
 [190 190 190 170 170 170]
 [255 255 255 255 255 255]]
```
Next, we specify our adaptive thresholding method:

```
img_thresh_adp = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 3, 7)
```
- **img:** This is the image we have translated into numbers using the cv2.imread method.
- **255:** This is the maximum value we are to use after calculations. This means that pixels that are above our result will be set to 255 (white) while the pixels that are below will be set to 0 (black)
- **cv2.ADAPTIVE_THRESH_MEAN_C:** This is the adaptiveThresholding algorithm. This method calculates the threshold for a pixel based on the mean of a certain number of pixels.
- **cv2.THRESH_BINARY:** THRESH_BINARY means that pixels above the threshold value will be set to the maximum value (255), and pixels below the threshold value will be set to 0.
- **3:** This means a 3 x 3 pixel area around each pixel is considered.
- **7:** This means after calculating the mean, we subtract 7 from it.

## Step-by-Step Calculation


**Block 1 (Top-left corner):**

Consider the 3x3 block starting at the top-left corner:

```
[[218 217 216]
 [211 210 210]
 [212 211 211]]

Mean: (218 + 217 + 216 + 211 + 210 + 210 + 212 + 211 + 211) / 9 = 212.8
Subtract constant from result: 212.8 - 7 = 205.8
```
Since every single number in block 1 is greater than 205, the numbers are all swapped for 255. Therefore the top left corner becomes this:

```
[[255 255 255]
 [255 255 255]
 [255 255 255]]
```

**Block 2:**

Consider the next 3x3 block:

```
[[217 216 221]
 [210 210 215]
 [211 211 214]]

Mean: 1925 / 9 = 213.8
Subtract constant: 213.8 - 7 = 206.8
```
Every single number in this block is greater than 206 so the numbers are all swapped for 255. Therefore the block becomes:

```
[[255 255 255]
 [255 255 255]
 [255 255 255]]
```

These calculations would be done row by row on a 3 x 3 basis until we have calculations for each section. If the current numbers are less than the result, we use 0 else we use 255. Also, note that the numbers are swapped for 255 only because that is what was specified as the maximum.

For example, below we have specified a maximum value of 200:
```
img_thresh_adp = cv2.adaptiveThreshold(img, 200, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 3, 7)

# Calculating the top left corner block
[[218 217 216]
 [211 210 210]
 [212 211 211]]

# Calculating the mean
Mean: 1916 / 9 = 212.8
Subtract constant: 212.8 - 7 = 205.8

# The result
[[200 200 200]
 [200 200 200]
 [200 200 200]]
```
 
The resulting image after will always contain a number between 0 and the maxValue specified.

I hope this clarifies adaptiveThresholding for someone out there!