1

I am using Open CV in python and I extracted some points from contour and pointpolygon test operation. (I basically used pointpolygon test to check if some pixels are inside a contour or not). Now I got the points but I want to visually confirm if the points I have are actually inside the contour or not. How to go about it? Ideally, I want to draw the contour first and then plot the extracted pixels. I can draw the contour using drawcontours functions but for plotting these points, only way I know is plt.scatter which is more using matplotlib instead of opencv.

There could be something fundamentally wrong in how I am approaching this because it feels like there should be an easier way to do this which I am missing. Here is a code snipper of what I have so far for reference.

Edit: Based on Mark Setchell's suggestion, added a code snippet where I am using image[x,y] to set color to a particular pixel. However, (x,y) is cartesian coordinate in my case and it does not work if I give it as pixel coordinate to the image.

import numpy as np
import cv2
import matplotlib.pyplot as plt

img = cv2.imread('ti.png',1)
plt.imshow(img)

ret, thresh = cv2.threshold(img, 250, 300, cv2.THRESH_BINARY_INV)

greySrc = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
laplacianSrc= cv2.Laplacian(greySrc, cv2.CV_8U, greySrc, ksize = 5)
contours, hierarchy=cv2.findContours(laplacianSrc, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)


indices = np.where(img!= [0])
coordinates = zip(indices[0], indices[1])
pts=list(coordinates)

in_or_out=[cv2.pointPolygonTest(contours[0],point,measureDist=False) for point in pts]
pts_ins_ctr=[x for x, y in zip(pts, in_or_out) if y == 1]
xi=[pts_ins_ctr[i][0] for i in range(len(pts_ins_ctr))]
yi=[pts_ins_ctr[i][1] for i in range(len(pts_ins_ctr))]

img[np.array(pts_ins_ctr)]=np.array([255,0,0],dtype=np.uint8)
plt.imshow(img)

Input Image enter image description here

output Image enter image description here

PagMax
  • 8,088
  • 8
  • 25
  • 40
  • cv2.drawcontour() for the contour. cv2.rectangle() or cv2.line() or cv2.circle with 2 points separated by 1 pixel or radius of 1 pixel. Or use numpy to insert a 1 pixel image into your image. – fmw42 Feb 12 '20 at 05:59
  • See https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_core/py_basic_ops/py_basic_ops.html if you just want to change the color of a given pixel. – fmw42 Feb 12 '20 at 06:09
  • Thanks @fmw42 I know drawcontour, rectangle, line etc but I have series of X, Y coordinates (pts_ins_contour). How do I plot them? – PagMax Feb 12 '20 at 06:21
  • `image[y,x]=255` will make that pixel white. – Mark Setchell Feb 12 '20 at 08:30
  • @MarkSetchell That is actually a good one and I am happy to learn but pixels coordinates are not same as x,y coordinates. So it is messing up my entire image. (Number of pixels is not same as number of x,y coordinates I have for the image) – PagMax Feb 12 '20 at 11:18
  • I don't understand! Maybe you could show a simple black image, 2 or 3 coordinates that you need to make white and how the result will look? – Mark Setchell Feb 12 '20 at 11:23
  • I will try to do that @MarkSetchell. In the meantime, let me explain again. I have X,Y points which are extracted from contour (pts_ins_ctr in above snippet). These are X, Y coordinates. There are total 3000 + of them. Now my entire image is 300 X 300 X3 pixel. So I tried to use your logic img[pts_ins_ctr]=255, and it is trying to whiten 3000+ pixels in 300 X 300 image. (Pretty much entire image turns white) – PagMax Feb 12 '20 at 11:27
  • I'm clearly misunderstanding something Here's what I get. A 300x300 pixel image will have 90,000 pixels. If I make 3,000 of them white, I am expecting around 3% to go white. – Mark Setchell Feb 12 '20 at 11:32
  • Adding full code/image in a minute. Well in that case, I have 3000 x coord and 3000 y coordinate. When I said 3000 points, I mean 3000 set of (x,y). – PagMax Feb 12 '20 at 11:36
  • @MarkSetchell Added complete code and reference simple image. First I am detecting the contour (circle) and now I want to paint red all the pixels in the circle. (My actual image is much more complicated than that) – PagMax Feb 12 '20 at 11:40
  • I still don't get it. Why don't you use `drawContours()` with the `filled` option? – Mark Setchell Feb 12 '20 at 11:56
  • Circle is used only as an example. Filling is not my objective. My contours are slightly complex and there are certain points in the contour I want to extract (using point polygon). Then I just want to plot and confirm, these points are actually inside the contour or not. – PagMax Feb 12 '20 at 12:11
  • In any case, by the method you suggested, this circle should be filled but as you can see it is not. – PagMax Feb 12 '20 at 12:12
  • Your approach is correct @MarkSetchell I figured out the problem.I do not know how to solve it but it is more of an indexing issue. I think I can fix it with some effort. Thanks for your help. – PagMax Feb 12 '20 at 13:03
  • Good! Glad we got there, sorry I couldn't immediately come up with a straightforward answer. Good luck with your project. – Mark Setchell Feb 12 '20 at 13:07

1 Answers1

1

This one solves it. Thanks @MarkSetchell

for pts in pts_ins_ctr:
    img[tuple(reversed(pts))]=[255,0,0]

Two things which worked

  1. Assigning color in loop instead of trying to assign all at once.
  2. im[y,x]=pix_color (As mark commented)
PagMax
  • 8,088
  • 8
  • 25
  • 40