2

I'm trying to find a way to read any any .png, .jpg or .tiff, and return the coordinates of all black or grey pixels in that image.

I'm thinking of having a certain threshold grey color, and writing out the coordinates of every pixel that is darker than that. I'm not sure how to manage the aspect of reading the image, however. I'm aiming to have my result be lists of all black pixels in the image, as such:

[x-coord, y-coord, black]

I've looked into using cv.imread to read out the coordinates of pixels, but as far as I've been able to tell, it works exactly opposite to the way I want it - it takes coordinates as a parameter, and returns the RGB values. Does anyone have tips / methods of making this work?

For anyone with similar questions, I solved this using the answer below, then I turned the numpy-array into a list using np.ndarray.tolist(). Additionally, since I only got a truncated version of the results, i used:

import sys

np.set_printoptions(threshold=sys.maxsize)

Now it was simple to print any element from the list using indices.

5
  • "it takes coordinates as a parameter, and returns the RGB values" suggests that this can be used in a double for loop to check the RGB values of every pixel in the image. Depending on your performance requirements, this should be a usable (though inefficient) way to determine which pixels are black. Commented Oct 15, 2019 at 15:43
  • Are your images colour? What do you plan to do with this list as the next phase? Do you have sample images? Commented Oct 15, 2019 at 18:25
  • I read them in greyscale using cv2.imread. The plan for the list is to use it to use it to display an image on an OLED display. I know there are easier ways to display pictures on OLEd, but this is the only format that will work, unfortunately. A sample image would be something rather simple such as this: angular.io/assets/images/logos/angular/angular_solidBlack.svg Commented Oct 15, 2019 at 18:52
  • Since you're using OpenCV, you can use the vectorized properties of Numpy to determine your pixel coordinates. When image processing try to avoid using double for-loops since it is extremely slow Commented Oct 15, 2019 at 21:56
  • Do you absolutely need the coordinates of the dark pixels, or would just having the pixels themselves suffice? What are you planning on doing once you have the coordinates? There might be a different way of doing things. Commented Oct 16, 2019 at 2:41

2 Answers 2

10

You can use np.column_stack() + np.where(). The idea is to convert the image to grayscale then find the coordinates of all pixels below a certain threshold. Note in grayscale, the image has one channel with pixel values [0 ... 255]


Using this input image with a threshold_level = 20

We color in all pixels below this threshold level in blue

All pixel coordinates can be determined from the mask using np.where() and stacked into (x, y) format with np.column_stack(). Here are all coordinates of pixels lower than the threshold

coords = np.column_stack(np.where(gray < threshold_level)) 
[[ 88 378] [ 89 378] [ 90 378] ... [474 479] [474 480] [474 481]] 

With threshold_level = 50:

[[ 21 375] [ 22 375] [ 23 376] ... [474 681] [474 682] [474 683]] 

Code

import cv2 import numpy as np image = cv2.imread('1.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Set threshold level threshold_level = 50 # Find coordinates of all pixels below threshold coords = np.column_stack(np.where(gray < threshold_level)) print(coords) # Create mask of all pixels lower than threshold level mask = gray < threshold_level # Color the pixels in the mask image[mask] = (204, 119, 0) cv2.imshow('image', image) cv2.waitKey() 

With your input image and threshold_level = 10

[[ 59 857] [ 59 858] [ 59 859] ... [1557 859] [1557 860] [1557 861]] 
Sign up to request clarification or add additional context in comments.

2 Comments

Fantastic, thank you for the explanation, this is really helpful. The only Thing I still do not understand is the following:
What I don't understand now is why print(coords) only returns 6 Pixels. I wrote "coords" into a new text file, and the Array was rather short, as in your example. Shouldn't there be many more pixels that fall within the threshhold Level, the way it looks in the Image that has been colored in. Regardless of the Image, there were always far too few rows that were printed. Am I misunderstanding how to read the Output?
0

Version that use PIL library

import numpy as np from PIL import Image image = Image.open("1.png").convert('L') pixels = np.asarray(image) # Set threshold level threshold_level = 50 # Find coordinates of all pixels below threshold coords = np.column_stack(np.where(pixels < threshold_level)) 

based on @nathancy answer, thank you for the code!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.