user13716575
user13716575

Reputation:

Grey scale image to contour with isotherm lines

I have gray scale image and want to convert to intensity contour with isotherm lines, in my code I am getting only one contour and how to apply the isotherm lines?

Goal:

enter image description here

import numpy as np
import cv2 as cv
img = cv2.imread(path)
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

cv.drawContours(img, contours, -1, (0,255,0), 3)

plt.imshow(img)

enter image description here

Upvotes: 2

Views: 625

Answers (2)

fmw42
fmw42

Reputation: 53164

Here is another approach in Python/OpenCV by quantizing the gray image and then getting the contours.

  • Read the input
  • Convert it to gray
  • Quantize it
  • Get Canny edge
  • Apply morphology close to ensure they are closed
  • Get the contours
  • Filter the contours by perimeter to remove small extraneous ones
  • Draw the contours on the input
  • Save the results


Input:

enter image description here

import numpy as np
import cv2

# read input
img = cv2.imread('bright_blob.png')

# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# do color quantization
gray = 64*((gray/64).astype(np.uint8))

# get canny edges
edges = cv2.Canny(gray, 10, 250)

# apply morphology closed to ensure they are closed
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)

# get contours
contours = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
contours = contours[0] if len(contours) == 2 else contours[1]

# filter contours to keep only large ones
result = img.copy()
for c in contours:
    perimeter = cv2.arcLength(c, True)
    if perimeter > 200: 
        cv2.drawContours(result, c, -1, (0,0,255), 1)

# save results
cv2.imwrite("bright_blob_gray.jpg", gray)
cv2.imwrite("bright_blob_edges.jpg", edges)
cv2.imwrite("bright_blob_isotherms.jpg", result)

# show images
cv2.imshow("gray", gray)
cv2.imshow("edges", edges)
cv2.imshow("result", result)
cv2.waitKey(0)


Quantized gray image:

enter image description here

Edge image:

enter image description here

Result:

enter image description here

Upvotes: 1

tiberius
tiberius

Reputation: 530

You're on the right track, all you have to do is just take that 127 that you hard-coded into the code, and iterate over a couple of different values. So take what you have and just add a few things (including a plug for the viridis colormap):

import numpy as np
import cv2 

# I don't have your image, so I will just create a similar one.
H, W = 480, 640 
img = np.zeros([H, W, 3], dtype=np.uint8)
cv2.circle(img, (W//2, H//2), 200, (255,255,255), -1) 
img = cv2.GaussianBlur(img, (551, 551), 0)
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# The viridis colormap is better than the jet one you have used.
img_viridis = cv2.applyColorMap(imgray, cv2.COLORMAP_VIRIDIS)

# This for-loop allows you to draw isotherm lines at any value you want.
THRESHES = [30, 90, 170]
for val in THRESHES:
    ret, thresh = cv2.threshold(imgray, val, 255, 0)
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, 
                          cv2.CHAIN_APPROX_SIMPLE)
    cv2.drawContours(img_viridis, contours, -1, (0, 0, 255), 2)

cv2.imshow('img', img_viridis)
k = cv2.waitKey(0)

output:
enter image description here

Upvotes: 1

Related Questions