0

I am new to image manipulation in python and would appreciate some advice on 2 problems.

I have an image: image and its mask:enter image description here

and open it as follows:

import cv2
import matplotlib.pyplot as plt

mask = cv2.imread('img_mask.jpg')
img = cv2.imread('img.jpg')

1) I have the following (x,y) pixel locations:

pt1 = 43.35, 22.49
pt2 = 49.035, 46.985
pt3 = 18.326, 21.822

On the mask, the pixel value at pt1 and pt2 is 0 and at pt3 it is 16. Given the three (x,y) pixel locations as a list, as well as the mask, as provided. How can I efficiently filter the locations whose value is 0 on the mask ?

2) How can I efficiently create a new thresholded masked image , then overlay it on the original image, such that the thresholded mask image is an image where the mask only has a value of 16 as obtained from pixel locations in the original mask where the values are 16.

user121
  • 849
  • 3
  • 21
  • 39
  • 1
    1. `mask` is an `np.array`, so you would be able to access it values as `mask[pt1[0], pt1[1]]` given the coordinates are integers. 2. `cv2.threshold` has an option `mask` that seems to work as you want. – Quang Hoang Feb 07 '19 at 19:50
  • no the coordinates being read in are non-integers at this point. – user121 Feb 07 '19 at 20:35
  • Just an FYI, you shouldn't use JPGs as masks. JPGs have small compression artifacts everywhere that change the values from what it was prior to being saved. See one of my previous answers [here](https://stackoverflow.com/a/44693722/5087436) which discusses why you shouldn't use `jpg`s as masks. – alkasm Feb 07 '19 at 21:41
  • @user121 use the coordinates to draw a polygon on a new blank mask. Then use that to mask your input mask. – alkasm Feb 07 '19 at 21:42
  • @AlexanderReynolds drawing a polygon is not feasible, simply because I may have cases where the points given are haphazard and do not always form a regular geometric polygon. – user121 Feb 07 '19 at 22:00
  • Remember again that the image is an `np.array`. Given the non-integer coordinates, what do you mean by pixel value at `pt1` is `0`? The answer to that question would be very related to the answer how to mask it. – Quang Hoang Feb 08 '19 at 03:03

1 Answers1

0

For the first part I don't know why your points are not integers. I downloaded the mask in the question and this code can be used to print the pairs having pixel value=0. I read the mask in grayscale format.

img = cv2.imread('mask.jpg',0)
for i in range(0,img.shape[0]):
    for j in range(0,img.shape[1]):
        if img[i,j] == 0:
            print(i,j)

For the second part normal thresholding can be used. Refer to opencv documentation for more on thresholding. I zoomed the image by 4 times to have a better view. Then two thresholds were created having threshold value of 16 and 17 and performing a bitwise xor of them to obtain the result.

zoom = cv2.resize(img, None, fx = 4, fy = 4, interpolation = cv2.INTER_CUBIC)
ret,thresh1 = cv2.threshold(zoom, 16, 255, cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(zoom, 17, 255, cv2.THRESH_BINARY)
output = cv2.bitwise_xor(thresh1, thresh2)
cv2.imshow('threshold with 16', thresh1)
cv2.imshow('threshold with more than 16', thresh2)
cv2.imshow('result', output)
cv2.waitKey(0)
cv2.destroyAllWindows()

mask with threshold as 16

Threshold 1

mask with threshold as 17

Threshold 2

mask with only pixels=16

Output

Vardan Agarwal
  • 2,023
  • 2
  • 15
  • 27
  • Some of OpenCV's functions return sub-pixel level precision, though I can't recall which. That may explain the non-integer coordinates. – Quang Hoang Feb 08 '19 at 16:07