How to label numbers on image with matrix position? (paint by numbers)

Viewed 324

First Process I did this

import numpy as np
import cv2
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
import numpy as np
img = cv2.imread("img.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 
img = np.array(img, dtype=np.float64) / 255
plt.imshow(img)

Then I took the image data to train to find the mean color by k-mean.

w, h, d = original_shape = tuple(img.shape)
print(w, h, d) # 627 783 3
img = np.reshape(img, (w * h, d))
img.shape # (490941, 3)
bit_of_color = 32
kmeans = KMeans(n_clusters=bit_of_color, random_state=0).fit(img)
labels = kmeans.predict(img)
kmeans.labels_ # array([16, 16, 16, ..., 28, 28, 28], dtype=int32)

After that, I created an image to display the color obtained from the model.

image = np.zeros((w, h, d))
mean_ = kmeans.cluster_centers_
d = mean_.shape[1]
mean_[1]

def adjust_image(mean_color_from_model, labels, w, h):
    d = mean_color_from_model.shape[1]
    print(mean_color_from_model.shape)
    image = np.zeros((w, h, d))
    label_idx = 0
    for i in range(w):
        for j in range(h):
            image[i][j] = mean_color_from_model[labels[label_idx]] 
            # print(image[i][j])
            label_idx += 1
    print(label_idx)
    return image

plt.axis('off')
img_kmean = adjust_image(kmeans.cluster_centers_, labels, w, h)
plt.imshow(img_kmean)

And get the following result. enter image description here

Next, I'll remove the color from the image and still the only the line of the object.

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('img2.png',0) 
edges = cv.Canny(img,100,200)
y, x = edges.shape
for i in range(y):
  for j in range(x):
    if (edges[i][j] == 0):
      edges[i][j] = 255
    elif (edges[i][j] == 255):
      edges[i][j] = 0
plt.imshow(edges,cmap = 'gray')
plt.show()

This is a result. enter image description here

Then, if I want to label a number into an image using the position of the matrix how to do that?

Desired result. (right image) enter image description here

Now, My process follows this. But it's still a mistake. How to make it better? enter image description here

Follow this Code

def check_bool(x, y, size_x, size_y):
    for j in range(y,y + size_y): 
      for k in range(x,x + size_x):  
        try:
          if (copy_edge[k][j] == 0): #255 W 0 B
            return False # ถ้าในกรอบเจอสีดำจะ set เป็น False และนำไป Plot ไม่ได้  
            break
        except:
            pass
    return True

def put_text(img_plt, text, x, y):
  cv2.putText(
              img_plt, #numpy array on which text is written
              str(text), #text
              (x,y), # x y
              cv2.FONT_HERSHEY_SIMPLEX, #font family
              0.5, #font size
              (0, 0, 0, 0), #font color
              2) #font stroke

size_x = 20
size_y = 20
copy_edge = edges.copy()
color_edge = img_kmean.copy()
y, x, d = color_edge.shape

for round in range(len(mean_color)):
  for y_ in range(0, y, size_y): 
    for x_ in range(0, x, size_x): 
      status = check_bool(x_, y_, size_x, size_y) # ถ้า Plot ได้
      # print(status)
      if status == True: # Putting text 
          c = sum(color_edge[y_][x_])
          c0 = sum(mean_color[round])
          if c == c0:
            put_text(copy_edge, round, x_, y_)
      
plt.figure(figsize = (17,10))
plt.imshow(copy_edge,cmap = 'gray')
plt.axis('off')
1 Answers

To label the pixels which are not 0 you can use opencv's cv2connectedComponentsWithStats() function

import numpy as np
import cv2 
from skimage.color import label2rgb 

# read the image as gray channel
I = cv2.imread("imgPath", 0)
# apply canny
edges = cv2.Canny(img,100,200)
# Invert the canny image
edges = 255 - edges

#dilating the mask to merge some edges(You can skip this step)
#edges = cv2.dilate(edges, np.ones((2,2)))
# label the bw mask from canny (white pixels are labelled automatically)
n, labels, _, _ = cv2.connectedComponentsWithStats(edges)
# convert the labels to RGB for visualization purpose
labels_rgb = np.uint8(255*label2rgb(labels, bg_label=0))
#save it
cv2.imwrite("./Pictures/bw.png", labels_rgb)

Inputoutput

Related