Skip to main content

10 OpenCV Algorithms for Image Recognition: From Pixels to Plate Detection

A practical walkthrough of 10 core OpenCV techniques—grayscale, blur, Canny edges, thresholding, contours, histograms, Harris corners, FAST, and a license plate case study—with Python code.

Why OpenCV Still Matters

OpenCV has been around for over two decades, and it's still the first tool many developers reach for when they need to process images. It's not the only game in town—deep learning frameworks get all the hype—but OpenCV gives you surgical control over pixels, edges, and shapes. That's useful when you're building something like a license plate reader or a quality inspection system, where you need to know exactly why a decision was made.

In this article, I'm going to walk through ten fundamental algorithms that form the backbone of classical computer vision. I'll keep the code short and the explanations practical. If you want to follow along, grab any image you like—a photo of your dog, a scanned document, whatever. The examples will work with just about anything.

1. Reading and Writing Images

Every vision project starts with loading an image. OpenCV makes this painfully simple:

import cv2
image = cv2.imread('example.jpg')
cv2.imshow('Image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

The imread function loads the file, imshow pops it on screen, and waitKey(0) keeps the window open until you press a key. Don't skip that last part—without it, the window flashes and disappears before you can blink.

Saving a processed image is just as trivial: cv2.imwrite('output.jpg', image). That one-liner is surprisingly handy when you're building a pipeline and want to inspect intermediate results.

2. Grayscale Conversion

Color images are great for humans, but they're heavy and often unnecessary for analysis. Converting to grayscale strips away the RGB channels and leaves you with a single intensity value per pixel. That reduces data size and makes features like edges and shapes pop.

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

Why BGR? OpenCV reads images in BGR order, not RGB. It's a quirk that trips up beginners, but once you know it, you'll stop pulling your hair out.

Try it on a landscape photo—the contours of mountains and rivers become much easier to see in grayscale.

3. Gaussian Blur for Noise Reduction

Raw images are noisy. Sensor noise, compression artifacts—all sorts of junk that messes with edge detection and other algorithms. Gaussian blur smooths the image by averaging each pixel with its neighbors, weighted by a Gaussian kernel.

blurred = cv2.GaussianBlur(image, (5, 5), 0)

The (5, 5) is the kernel size; larger kernels mean more blur. The 0 is the standard deviation, which OpenCV computes automatically if you leave it as zero.

Blurring is a preprocessing step, not a final destination. I rarely use it for aesthetics—it's almost always to clean up an image before I run Canny or a contour detector.

4. Canny Edge Detection

Edges are where the action is. The Canny algorithm is the gold standard for edge detection, and OpenCV makes it a one-liner:

edges = cv2.Canny(gray, 50, 150)

The two numbers are threshold values. Pixels with gradient magnitudes above 150 are considered strong edges; those below 50 are discarded. Anything in between is kept only if it's connected to a strong edge. That hysteresis trick reduces false positives.

You'll see a black-and-white image where white pixels mark the edges. Canny is the workhorse behind many real-world systems, from lane detection to medical imaging.

5. Thresholding: Turning Grayscale into Binary

Thresholding is the simplest way to separate an object from its background. You pick a value—say, 127—and every pixel above it becomes white, every pixel below becomes black.

_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

But global thresholds fail when lighting varies across the image. That's where adaptive thresholding comes in. It computes a threshold for small local regions, so it handles shadows and glare much better:

adaptive = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)

The 11 is the block size, and 2 is a constant subtracted from the local mean. Tweak those based on your image resolution.

6. Contour Detection

Once you have a binary image, you can find the actual shapes. Contours are curves that join all the continuous points along a boundary. OpenCV's findContours is the tool:

contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(output, contours, -1, (0, 255, 0), 2)

In this snippet, I'm using the Canny edges from before, then drawing the contours in green. The RETR_EXTERNAL flag grabs only the outermost contours, which is useful when you don't care about holes inside objects.

Contour detection is how you locate objects in an image—whether it's a defective part on a conveyor belt or a stop sign in a self-driving car.

7. Histograms and Equalization

A histogram shows how many pixels have each intensity value. It's a quick way to judge an image's brightness and contrast. OpenCV's calcHist does the counting, and you can plot it with matplotlib:

hist = cv2.calcHist([gray], [0], None, [256], [0, 256])

If the histogram is bunched in the middle, your image is low-contrast. Fix that with equalization:

equ = cv2.equalizeHist(gray)

This spreads out the intensity values, making details pop. I've used it to salvage underexposed photos before running OCR.

8. Harris Corner Detection

Corners are points where the image intensity changes sharply in multiple directions. They're great anchor points for tracking and matching. Harris corner detection is a classic algorithm that computes a score for each pixel based on the local gradient structure.

gray_float = np.float32(gray)
dst = cv2.cornerHarris(gray_float, blockSize=2, ksize=3, k=0.04)
img[dst > 0.01 * dst.max()] = [0, 0, 255]

The threshold 0.01 * dst.max() is a heuristic—you might need to tune it. The blockSize is the window size, and ksize is the Sobel kernel size. Harris corners are still used in camera calibration and 3D reconstruction.

9. FAST Feature Detection

Harris is accurate but slow. If you need speed, FAST (Features from Accelerated Segment Test) is the way to go. It works by comparing a pixel to a circle of 16 neighboring pixels—if at least 12 of them are all brighter or all darker, it's a keypoint.

fast = cv2.FastFeatureDetector_create()
keypoints = fast.detect(gray, None)
result = cv2.drawKeypoints(gray, keypoints, None, color=(255, 0, 0))

FAST is blazing fast, which makes it perfect for real-time applications like tracking features in video. It doesn't have scale or rotation invariance, but for many tasks, you don't need that.

10. A Mini License Plate Reader

Let's put it all together. A classic demo is reading a license plate from a car photo. Here's the plan:

  1. Convert to grayscale and blur to reduce noise.
  2. Run Canny edge detection to find boundaries.
  3. Find contours and filter by aspect ratio (plates are wider than they are tall).
  4. Extract the plate region, threshold it, and feed it to Tesseract OCR.
edges = cv2.Canny(gray, 50, 150)
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
x, y, w, h = cv2.boundingRect(c)
if 2 < w/h < 6 and cv2.contourArea(c) > 500:
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
plate = gray[y:y+h, x:x+w]
_, thresh = cv2.threshold(plate, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
text = pytesseract.image_to_string(thresh, config='--psm 7')
print('Plate:', text.strip())

That's a real pipeline in about fifteen lines. It won't win any competitions, but it shows how the basics fit together.

Where to Go Next

These ten algorithms are the foundation. Once you're comfortable with them, you can move on to more advanced topics like SIFT, SURF, or even deep learning with OpenCV's DNN module. But don't skip the fundamentals—they're the difference between blindly calling a neural network and actually understanding what's happening under the hood.

Grab an image and start experimenting. Change the kernel sizes, tweak the thresholds, see how the output shifts. That hands-on tinkering is how you'll really learn.

Share this article:

Comments (0)

No comments yet. Be the first to comment!