Search code examples
pythonimage-processingscikit-imagepeakutils

Best Method to annotate Image using python


I'm trying to align text boxes with the red dots but I have no idea where to start. Any advice/examples would be appreciated.

My image


I used skimage and peakutils to get the locations of the ladder bands and lanes and now I would like to annotate them

%matplotlib inline
import skimage
import numpy as np
import matplotlib.pyplot as plt 
from skimage import data
from skimage import io
from skimage.color import rgb2gray
from skimage.filters import threshold_otsu
from skimage.util import invert, crop
import peakutils
from peakutils.plot import plot as pplot
import pandas as pd
from scipy.misc import toimage
from skimage import feature

def ladder_peaks(image):
    image = io.imread(image)
    image_grey = rgb2gray(image)
    image_grey = invert(image_grey)
    image_otsu = threshold_otsu(image_grey)
    image_otsu = image_grey > image_otsu
    xi,yi = image_otsu.shape
    width_per_lane=int(xi/10)
    imagecopy_otsu = np.copy(image_otsu)
    imagecopy_otsu = imagecopy_otsu[:,0:(width_per_lane*2)]
    ladder_mean = imagecopy_otsu.mean(1)
    count = 0
    x = []
    for i in ladder_mean:
        x.append(count)
        count+=1
    x = np.asarray(x)
    indexes = peakutils.indexes(ladder_mean, thres=0.4, min_dist=80)
    indexes = indexes.tolist()
    origin = image
    for i in indexes:
        image[i:(i+30),0:30,:] = [255,0,0]
    io.imshow(image)

Solution

  • Here is an implementation of how to accomplish this is in opencv. I will try to explain as much as necessary.

    Import the necessary libraries.

    import cv2
    import numpy as np
    

    Now open the file for opencv to read

    image = cv2.imread('images/red-dots.jpg')
    

    Keep an original copy since we will be manipulating the first image.

    original_image = image
    

    Now convert the color format from the default BGR to RGB. This step is not imperative and I encourage you to try this in the BGR color format as an exercise.

    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    

    Now set your upper and lower limits to help us zone in on only the red hues.

    min_red= np.array([210, 0, 0])
    max_red = np.array([255, 33, 33])
    

    The inRange function will allow us to ignore everything that is not between our limits.

    image_red = cv2.inRange(image, min_red, max_red )
    

    Run a canny filter; this will detection our edges.

    edged = cv2.Canny(image_red, 50, 200)
    

    Now we want to generate our contours, notice the flags. We only want simple contours.

    contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    

    This function will find the centroids of our contours. The "magic" of cv2.moments makes this easy for us. Next it places text around the location of the contour's centroid.

    def label_contour_center(image, c):
        # Places some text over the contours
            M = cv2.moments(c)
            cx = int(M['m10'] / M['m00'])
            cy = int(M['m01'] / M['m00'])
            cv2.putText(image, "#{}".format(i + 1), (cx, cy), cv2.FONT_HERSHEY_SIMPLEX, .3, (255,150,250), 1)
            return image
    

    Now the enumerate function will help us keep track of how many contours we have stored. Think of i as a count variable and c as the variable that contains data for every individual contour.

    for i,c in enumerate(contours):
        orig = label_contour_center(original_image, c)
    

    Now show the image, and destroy it upon a keyboard event.

    cv2.imshow('Red dots', original_image)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()