4

i am using python with opencv and numpy, to detect stars in astronomical for example this one1 images. Using template matching I have got it to detect stars with a threshold (click the 2) 2 by drawing a rectangle around a star template. My next goal is to essentially "remove" the stars from the image.

To do this, I have tried blurring the image with different methods, cv2.blur etc, but it doesn't create the effect i am looking for. My next idea was to get rgb data from pixels around the star, average them out, and color in the star with the selected colour. Is this the best option and how would i do this?

my code is as below.

import cv2
import numpy as np
import time

start = time.time()
threshold = 0.4
image = cv2.imread('lag.jpg')
imageG = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#cv2.imshow('original', image)
#cv2.imshow('greyscale', imageG)

template = cv2.imread('template.jpg', 0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(imageG,template,cv2.TM_CCOEFF_NORMED)
loc = np.where( res >= threshold)

for pt in zip(*loc[::-1]):
    a = cv2.rectangle(image, pt, (pt[0] + w, pt[1] + h), (0,0,255), 1)


cv2.imshow('lag.jpg', image)
end = time.time()
final = end - start
print(final)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 2
    Please provide an input image, so we can see what you are doing? You should not need template matching unless you have larger than point objects. You could just threshold. Then get contours. Then filter contours on area or some other measure. – fmw42 Jun 22 '21 at 18:38
  • I know its late. But for people having same problem I want to suggest to use astronomical tools such as PSF (Point Spread Function). PSF is the best estimation of a star on an image. So one can create a 3D profile of a star and since the 3D profile is available removing it will be easy: https://photutils.readthedocs.io/en/stable/psf.html – MSH Jul 13 '22 at 13:20

1 Answers1

6

You may create a mask, and use cv2.inpaint for replacing the selected "mask area" using the pixel near the area boundary.

Since you didn't post 'template.jpg', I created the following one:
enter image description here


  • Building a mask by drawing filled rectangles on zeros image:

     mask = np.zeros_like(imageG)
     for pt in zip(*loc[::-1]):
         #a = cv2.rectangle(image, pt, (pt[0] + w, pt[1] + h), (0,0,255), 1)
         cv2.rectangle(mask, (pt[0]+3, pt[1]+3), (pt[0]+w-3, pt[1]+h-3), 255, -1)  # Reduce the size of the rectangle by 3 pixels from each side.
    

    Note: I used cv2.rectangle for keeping your original code, but I think circles may by better in your case.

  • Using inpaint for removing the masked area:

     image = cv2.inpaint(image, mask, 2, cv2.INPAINT_NS)
    

    You may tune the parameters.


Here is the complete code:

import cv2
import numpy as np
import time

start = time.time()
threshold = 0.4
image = cv2.imread('lag.jpg')
imageG = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

#template = cv2.imread('template.jpg', 0)
template = cv2.imread('template.png', 0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(imageG,template,cv2.TM_CCOEFF_NORMED)
loc = np.where( res >= threshold)


mask = np.zeros_like(imageG)
for pt in zip(*loc[::-1]):
    #a = cv2.rectangle(image, pt, (pt[0] + w, pt[1] + h), (0,0,255), 1)
    cv2.rectangle(mask, (pt[0]+3, pt[1]+3), (pt[0]+w-3, pt[1]+h-3), 255, -1)  # Reduce the size of the rectangle by 3 pixels from each side


image = cv2.inpaint(image, mask, 2, cv2.INPAINT_NS)

cv2.imshow('lag.jpg', image)
cv2.imshow('mask', mask)
end = time.time()
final = end - start
print(final)
cv2.waitKey(0)
cv2.destroyAllWindows()

Results:

mask:
enter image description here

image (after inpaint):
enter image description here

Original image (for comparison):
enter image description here


You may improve the solution using few sizes of rectangles (or circles) - use larger rectangles for covering the larger stars.

Rotem
  • 30,366
  • 4
  • 32
  • 65