initial commit of new version
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
# color_features_tiles.py - color features tiled data from images
|
||||
# ImageDB2 - Tools for analysis, indexing, search, and creative use of image data
|
||||
|
||||
"""
|
||||
ColorFeaturesTiles
|
||||
Part of ImageDB2 - Tools for analysis, indexing, search, and creative use of image data
|
||||
|
||||
Overview
|
||||
========
|
||||
Pyramid down-sampling + color-feature analysis.
|
||||
Saves downsampled data to NAME.COLORSPACE.TILE{SIZE}.OLAP{SIZE} data files mem-mapped to np arrays.
|
||||
Also retrieves and displays tiled image data.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import math
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
from dataclasses import dataclass
|
||||
|
||||
from avdb.config import (
|
||||
check_params,
|
||||
NUM_HISTO_BINS,
|
||||
LEVELS_CONFIG
|
||||
)
|
||||
|
||||
|
||||
class ColorFeaturesTile(object):
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, **params) -> None:
|
||||
self.uuid = check_params(params, 'uuid', 'TESTIMG')
|
||||
self.root_path = check_params(params, 'root_path', '/home/kfl/dev/git/avdb-py-v1')
|
||||
self.level = check_params(params, 'level', 0)
|
||||
self.colorspace = check_params(params, 'color_space', 'lab')
|
||||
self.write_flag = True
|
||||
self.debug = True
|
||||
print(f"CREATING TILE -- LEVEL: {self.level} - UUID: {self.uuid} color space: {self.colorspace} - write_flag: {self.write_flag}")
|
||||
|
||||
def analyze_img_tiles_postnorm(self, lvl=None):
|
||||
"""
|
||||
"""
|
||||
if lvl is None:
|
||||
imgpath = f"{self.root_path}/img/{self.uuid}/{self.uuid}.jpeg"
|
||||
else:
|
||||
imgpath = f"{self.root_path}/img/{self.uuid}/{self.uuid}.{self.colorspace}.pyr_{lvl}.jpeg"
|
||||
|
||||
print(imgpath)
|
||||
img = cv.imread(imgpath, cv.IMREAD_UNCHANGED)
|
||||
imgw = img.shape[1]
|
||||
imgh = img.shape[0]
|
||||
|
||||
# iterate over the tiles and unroll into linear chunks
|
||||
def _aux():
|
||||
for top_crnr in range(imgh):
|
||||
for lft_crnr in range(imgw):
|
||||
# print(img[top_crnr, lft_crnr])
|
||||
yield np.r_[
|
||||
img[top_crnr,lft_crnr],
|
||||
]
|
||||
|
||||
total_tiles = np.c_[list(_aux())]
|
||||
|
||||
if self.write_flag is True:
|
||||
print(imgpath)
|
||||
mmappath = f"{imgpath}.tiles.mmap"
|
||||
|
||||
fp = np.memmap(
|
||||
mmappath,
|
||||
dtype=np.uint16,
|
||||
mode="w+",
|
||||
shape=total_tiles.shape
|
||||
)
|
||||
print(f"all tiles : {total_tiles.shape}")
|
||||
fp[:] = total_tiles
|
||||
fp.flush()
|
||||
|
||||
return total_tiles, (imgw, imgh, 1, 1)
|
||||
|
||||
def analyze_img_blocks_postnorm(self, lvl=None):
|
||||
"""
|
||||
"""
|
||||
if lvl is None:
|
||||
imgpath = f"{self.root_path}/img/{self.uuid}/{self.uuid}.jpeg"
|
||||
else:
|
||||
imgpath = f"{self.root_path}/img/{self.uuid}/{self.uuid}.{self.colorspace}.pyr_{lvl}.jpeg"
|
||||
|
||||
print(imgpath)
|
||||
img = cv.imread(imgpath, cv.IMREAD_UNCHANGED)
|
||||
imgw = img.shape[1]
|
||||
imgh = img.shape[0]
|
||||
|
||||
target_blocks = LEVELS_CONFIG[lvl]["targetblocks"]
|
||||
|
||||
if target_blocks is None:
|
||||
raise ValueError(f"target_blocks is None for level {self.level}")
|
||||
|
||||
# calculate gutters
|
||||
imgw -= 2
|
||||
imgh -= 2
|
||||
|
||||
# iterate over the blocks and unroll into linear chunks
|
||||
def _aux():
|
||||
for top_crnr in range(imgh):
|
||||
for lft_crnr in range(imgw):
|
||||
yield np.r_[
|
||||
img[top_crnr,lft_crnr:lft_crnr+3],
|
||||
img[top_crnr+1,lft_crnr:lft_crnr+3],
|
||||
img[top_crnr+2,lft_crnr:lft_crnr+3]
|
||||
].flatten()
|
||||
|
||||
total_blocks = np.c_[list(_aux())]
|
||||
|
||||
if self.write_flag is True:
|
||||
print(imgpath)
|
||||
mmappath = f"{imgpath}.blocks.mmap"
|
||||
|
||||
fp = np.memmap(
|
||||
mmappath,
|
||||
dtype=np.uint16,
|
||||
mode="w+",
|
||||
shape=total_blocks.shape
|
||||
)
|
||||
print(f"all histograms : {total_blocks.shape}")
|
||||
fp[:] = total_blocks
|
||||
fp.flush()
|
||||
|
||||
return total_blocks, (imgw, imgh, 1, 1)
|
||||
|
||||
def analyze_img_histograms_postnorm(self, lvl=None):
|
||||
"""
|
||||
overlapping tiles analysis
|
||||
+ width in tiles must be a multiple of 2
|
||||
"""
|
||||
if lvl is None:
|
||||
imgpath = f"{self.root_path}/img/{self.uuid}/{self.uuid}.jpeg"
|
||||
else:
|
||||
imgpath = f"{self.root_path}/img/{self.uuid}/{self.uuid}.{self.colorspace}.pyr_{lvl}.jpeg"
|
||||
|
||||
print(imgpath)
|
||||
img = cv.imread(imgpath, cv.IMREAD_UNCHANGED)
|
||||
imgw = img.shape[1]
|
||||
imgh = img.shape[0]
|
||||
|
||||
# / by 1 = whole dimension
|
||||
gridsplit = LEVELS_CONFIG[lvl]["gridsplit"]
|
||||
tilesw = (gridsplit + 1) if gridsplit is not None else 1
|
||||
tilesh = (gridsplit + 1) if gridsplit is not None else 1
|
||||
|
||||
tilew = int(imgw / tilesw)
|
||||
tileh = int(imgh / tilesh)
|
||||
|
||||
# img = self.convert_colorspace(img)
|
||||
mask = np.zeros(img.shape[:2], np.uint8)
|
||||
|
||||
all_histograms = np.array([], dtype=np.float32)
|
||||
all_histograms.shape = (0, 1)
|
||||
|
||||
lastx, lasty = 0, 0
|
||||
|
||||
print(f"dims: {(tilesw,tilesh)}")
|
||||
|
||||
for y in range(tilesh):
|
||||
|
||||
for x in range(tilesw):
|
||||
|
||||
if (lastx, lasty) != (x, y):
|
||||
mask[
|
||||
int(tilew/2 * lastx) : int((tilew/2 * lastx) + tilew),
|
||||
int(tileh/2 * lasty) : int((tileh/2 * lasty) + tileh),
|
||||
] = 0
|
||||
|
||||
lastx = x
|
||||
lasty = y
|
||||
|
||||
mask[
|
||||
int(tilew/2 * x) : int((tilew/2 * x) + tilew),
|
||||
int(tileh/2 * y) : int((tileh/2 * y) + tileh),
|
||||
] = 255
|
||||
|
||||
# calculate 3 channels' histograms
|
||||
hist0_masked = cv.calcHist(
|
||||
[img], [0], mask, [NUM_HISTO_BINS], [0, 65536]
|
||||
)
|
||||
hist0_masked.shape = (NUM_HISTO_BINS, 1)
|
||||
row0 = hist0_masked
|
||||
|
||||
hist1_masked = cv.calcHist(
|
||||
[img], [1], mask, [NUM_HISTO_BINS], [0, 256]
|
||||
)
|
||||
hist1_masked.shape = (NUM_HISTO_BINS, 1)
|
||||
row1 = hist1_masked
|
||||
|
||||
hist2_masked = cv.calcHist(
|
||||
[img], [2], mask, [NUM_HISTO_BINS], [0, 256]
|
||||
)
|
||||
hist2_masked.shape = (NUM_HISTO_BINS, 1)
|
||||
row2 = hist2_masked
|
||||
|
||||
# print(f"row0: {row0} - {row0.shape}")
|
||||
# print(f"row1: {row1} - {row1.shape}")
|
||||
# print(f"row2: {row2} - {row2.shape}")
|
||||
|
||||
# L [bin0,bin1,..bin15], r=0, c=0
|
||||
# A [bin0,bin1,..bin15]
|
||||
# B [bin0,bin1,..bin15]
|
||||
|
||||
# L [bin0,bin1,..bin15], r=0, c=1
|
||||
# A [bin0,bin1,..bin15]
|
||||
# B [bin0,bin1,..bin15]
|
||||
|
||||
# etc.
|
||||
# top left to bottom right
|
||||
|
||||
all_histograms: np.array = np.r_[
|
||||
all_histograms, row0, row1, row2
|
||||
]
|
||||
|
||||
# print(f"ALL HISTOGRAMS: {all_histograms.shape}")
|
||||
# print(all_histograms[-48:,:])
|
||||
|
||||
total_hist = np.reshape(all_histograms[:], (-1,48))
|
||||
|
||||
sz = tilesh * tilesw
|
||||
|
||||
cv.normalize(
|
||||
total_hist, total_hist, norm_type=cv.NORM_MINMAX
|
||||
)
|
||||
|
||||
# total_hist *= 255.
|
||||
|
||||
print(f"total HISTOGRAM: {total_hist.shape} {total_hist.sum()}")
|
||||
|
||||
print(total_hist[:2,:])
|
||||
print(np.max(total_hist, 0)[:24])
|
||||
print(np.max(total_hist, 1)[:24])
|
||||
|
||||
print(np.min(total_hist, 0)[:24])
|
||||
print(np.min(total_hist, 1)[:24])
|
||||
|
||||
print(np.mean(total_hist, 0)[:24])
|
||||
print(np.mean(total_hist, 1)[:24])
|
||||
|
||||
if self.write_flag is True:
|
||||
print(f"writing to: {imgpath}.histos.mmap")
|
||||
mmappath = f"{imgpath}.histos.mmap"
|
||||
|
||||
fp = np.memmap(
|
||||
mmappath,
|
||||
dtype="float32",
|
||||
mode="w+",
|
||||
shape=total_hist.shape
|
||||
)
|
||||
print(f"all histograms : {total_hist.shape}")
|
||||
fp[:] = total_hist
|
||||
# print(f"CHECK: {fp[:2,:]} - {np.max(fp)} - {np.min(fp)}")
|
||||
fp.flush()
|
||||
|
||||
return total_hist, (imgw, imgh, tilesw, tilesh)
|
||||
Reference in New Issue
Block a user