Digitizing heatmap and map pixels to values

情到浓时终转凉″ 提交于 2021-02-05 11:52:41

问题


I'd like to digitize a heatmap, Panel D in this source

image

As a first step, I tried to read the image in opencv and obtain a matrix

import cv2
from pprint import pprint


def read_as_digital(image):
    # mage dimensions
    h = image.shape[0]
    w = image.shape[1]
    print(h, w)
    pass


if __name__ == '__main__':

    image = cv2.imread('ip.jpg', 1)
    pprint(image)

    read_as_digital(image)

I could read the image as a matrix, but I don't know how to specify the beginning of the cells (corresponding to different subplots in panel D of the image) in the heatmap. finally, I want to map the pixels to values.

Any suggestions on how to proceed will be really helpful

EDIT1:

I tried to obtain the values on click

For instance, when I consider a small subsection of the heatmap provided in the source

I expect to obtain the average value for each cell (centered around yellow dots) in the image. Clicking at different points yields different values. Clicking on the cell that's coored gives different RGB values at different points.

Any suggestion on how to obtain an average value for each cell (e.g.) will be really helpful.

EDIT2:

I've tried the updated code.

The mean average for this ((e.g.)) works really well. However, there is a problem with the cell next to it. When I click the adjacent cell, the mean that is displayed by the code is for 3 cells that are with the same color. It would be really nice if there is a way to limit the cell size, kind of specify a boundary in which the mean should be calculated in the code. The image presented in edit 1 has 6 rows and 6 columns. If we view this as 6 by 6 matrix say, A, the mean should be obtained for each Aijth entry of the matrix.


回答1:


import cv2
import numpy as np

# print pixel value on click
def mouse_callback(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONDOWN:
        # get specified color
        row = y
        column = x
        color = image[row, column]
        print('color = ', color)
        # calculate range
        thr = 20  # ± color range
        up_thr = color + thr
        up_thr[up_thr < color] = 255
        down_thr = color - thr
        down_thr[down_thr > color] = 0
        # find points in range
        img_thr = cv2.inRange(image, down_thr, up_thr)  # accepted range
        height, width, _ = image.shape
        left_bound = x - (x % round(width/6))
        right_bound = left_bound + round(width/6)
        up_bound = y - (y % round(height/6))
        down_bound = up_bound + round(height/6)
        img_rect = np.zeros((height, width), np.uint8)  # bounded by rectangle
        cv2.rectangle(img_rect, (left_bound, up_bound), (right_bound, down_bound), (255,255,255), -1)
        img_thr = cv2.bitwise_and(img_thr, img_rect)
        # get points around specified point
        img_spec = np.zeros((height, width), np.uint8)  # specified mask
        last_img_spec = np.copy(img_spec)
        img_spec[row, column] = 255
        kernel = np.ones((3,3), np.uint8)  # dilation structuring element
        while cv2.bitwise_xor(img_spec, last_img_spec).any():
            last_img_spec = np.copy(img_spec)
            img_spec = cv2.dilate(img_spec, kernel)
            img_spec = cv2.bitwise_and(img_spec, img_thr)
            cv2.imshow('mask', img_spec)
            cv2.waitKey(10)
        avg = cv2.mean(image, img_spec)[:3]
        print('mean = ', np.around(np.array(avg), 2))
        global avg_table
        avg_table[:, 6 - int(x / (width/6)), 6 - int(y / (height/6))] = avg
        print(avg_table)

# average value of each cell in 6x6 matrix
avg_table = np.zeros((3, 6, 6))

# create window and callback
winname = 'img'
cv2.namedWindow(winname)
cv2.setMouseCallback(winname, mouse_callback)

# read & display image
image = cv2.imread('ip.jpg', 1)
image = image[3:62, 2:118]  # crop the image to 6x6 cells
cv2.imshow(winname, image)
cv2.waitKey()  # press any key to exit
cv2.destroyAllWindows()

Note that OpenCV has BGR color format instead of RGB. So, clicking on the red color will print out [0, 0, 255], for instance.

You can change thr to adjust range for accepted colors.

The image is cropped to include only 6 by 6 matrix part.



来源:https://stackoverflow.com/questions/60777750/digitizing-heatmap-and-map-pixels-to-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!