680 lines
23 KiB
Python
680 lines
23 KiB
Python
import os
|
|||
|
|
import re
|
||
|
|
import json
|
||
|
|
import uuid
|
||
|
|
import csv
|
||
|
|
from typing import List, Tuple
|
||
|
|
import psycopg2
|
||
|
|
from psycopg2 import extras
|
||
|
|
import numpy as np
|
||
|
|
import cv2 as cv
|
||
|
|
|
||
|
|
from avdb.config import LEVELS_CONFIG
|
||
|
|
|
||
|
|
BATCH_SIZE=200
|
||
|
|
|
||
|
|
class DBConnection:
|
||
|
|
def __init__(self, dbname='testdb'):
|
||
|
|
try:
|
||
|
|
self._connection = psycopg2.connect(
|
||
|
|
user="postgres",
|
||
|
|
password='pgRocks',
|
||
|
|
host="127.0.0.1",
|
||
|
|
port="5432",
|
||
|
|
database=dbname
|
||
|
|
)
|
||
|
|
print(f"\nconnection: {self._connection}\n\n")
|
||
|
|
self._connection.autocommit = True
|
||
|
|
self.dbname = dbname
|
||
|
|
# Create a cursor to execute queries
|
||
|
|
self.cursor = self._connection.cursor()
|
||
|
|
|
||
|
|
# Print PostgreSQL details
|
||
|
|
print("PostgreSQL server information")
|
||
|
|
print(self._connection.get_dsn_parameters(), "\n")
|
||
|
|
|
||
|
|
# Executing a SQL query
|
||
|
|
self.cursor.execute("SELECT version();")
|
||
|
|
|
||
|
|
# Fetch result
|
||
|
|
record = self.cursor.fetchone()
|
||
|
|
print("You are connected to - ", record, "\n")
|
||
|
|
|
||
|
|
except (Exception, psycopg2.Error) as error:
|
||
|
|
print("Error while connecting to PostgreSQL", error)
|
||
|
|
|
||
|
|
def get_cursor(self):
|
||
|
|
return self._connection.cursor()
|
||
|
|
|
||
|
|
def get_connection(self):
|
||
|
|
return self._connection
|
||
|
|
|
||
|
|
def test_db_connection():
|
||
|
|
"""
|
||
|
|
Test if the database is active and available by attempting a connection and a simple query.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
bool: True if the database connection is successful, False otherwise.
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
# Attempt to establish a connection
|
||
|
|
conn = DBConnection('testdb')
|
||
|
|
cursor = conn.get_cursor()
|
||
|
|
|
||
|
|
# Execute a simple query to verify the connection
|
||
|
|
cursor.execute("SELECT 1;")
|
||
|
|
result = cursor.fetchone()
|
||
|
|
|
||
|
|
if result[0] == 1:
|
||
|
|
print("Database connection test successful!")
|
||
|
|
return True
|
||
|
|
else:
|
||
|
|
print("Database connection test failed.")
|
||
|
|
return False
|
||
|
|
|
||
|
|
except (Exception, psycopg2.Error) as error:
|
||
|
|
print(f"Error while testing database connection: {error}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
class DBOps:
|
||
|
|
def __init__(self, connection):
|
||
|
|
# self._dbname = connection.dbname
|
||
|
|
self._connection = connection
|
||
|
|
|
||
|
|
def insert_image(
|
||
|
|
self,
|
||
|
|
img_path: str,
|
||
|
|
img_name: str,
|
||
|
|
width: int,
|
||
|
|
height: int,
|
||
|
|
img_id= None
|
||
|
|
) -> int:
|
||
|
|
"""
|
||
|
|
Insert a new image record into the images table.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
img_path (str): Path to the image file.
|
||
|
|
img_name (str): Name of the image file.
|
||
|
|
width (int): Width of the image in pixels.
|
||
|
|
height (int): Height of the image in pixels.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
int: The ID of the newly inserted image record.
|
||
|
|
"""
|
||
|
|
print(f"Inserting image: {img_path},{img_id}")
|
||
|
|
query_str = """
|
||
|
|
INSERT INTO avdb_image (img_path, img_name, width, height)
|
||
|
|
VALUES (%s, %s, %s, %s)
|
||
|
|
RETURNING img_id;
|
||
|
|
"""
|
||
|
|
with self._connection.get_cursor() as cursor:
|
||
|
|
cursor.execute(query_str, (img_path, img_name, width, height))
|
||
|
|
img_id_out = cursor.fetchone()[0]
|
||
|
|
print(f"Warning if true: {img_id != img_id_out}")
|
||
|
|
return img_id_out
|
||
|
|
|
||
|
|
def insert_histogram_data(
|
||
|
|
self,
|
||
|
|
img_id: int,
|
||
|
|
level: int,
|
||
|
|
tilex: int,
|
||
|
|
tiley: int,
|
||
|
|
x: int,
|
||
|
|
y: int,
|
||
|
|
x0: int,
|
||
|
|
y0: int,
|
||
|
|
w: int,
|
||
|
|
h: int,
|
||
|
|
histogram_data: List[float]
|
||
|
|
) -> int:
|
||
|
|
"""
|
||
|
|
Insert histogram data into the histogramfeatures table.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
img_id (int): ID of the image.
|
||
|
|
level (int): Pyramid level.
|
||
|
|
tilex (int): Logical tile x-coordinate.
|
||
|
|
tiley (int): Logical tile y-coordinate.
|
||
|
|
x (int): Upper left x-coordinate (in original resolution).
|
||
|
|
y (int): Upper left y-coordinate (in original resolution).
|
||
|
|
x0 (int): Upper left x-coordinate (in down-sampled resolution).
|
||
|
|
y0 (int): Upper left y-coordinate (in down-sampled resolution).
|
||
|
|
w (int): Width of the histogram region.
|
||
|
|
h (int): Height of the histogram region.
|
||
|
|
histogram_data (np.ndarray): Histogram data as a numpy array.
|
||
|
|
[tile_data: NULL.]
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
int: The ID of the newly inserted histogram record.
|
||
|
|
"""
|
||
|
|
query_str = """
|
||
|
|
INSERT INTO pyramiddata (
|
||
|
|
img_id, level, tilex, tiley, x, y, x0, y0, w, h, hash, histogram
|
||
|
|
)
|
||
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||
|
|
RETURNING pyrdata_id;
|
||
|
|
"""
|
||
|
|
hsh = uuid.uuid4()
|
||
|
|
with self._connection.cursor() as cursor:
|
||
|
|
cursor.execute(
|
||
|
|
query_str,
|
||
|
|
(
|
||
|
|
img_id,
|
||
|
|
level,
|
||
|
|
tilex,
|
||
|
|
tiley,
|
||
|
|
x,
|
||
|
|
y,
|
||
|
|
x0,
|
||
|
|
y0,
|
||
|
|
w,
|
||
|
|
h,
|
||
|
|
str(hsh),
|
||
|
|
histogram_data
|
||
|
|
)
|
||
|
|
)
|
||
|
|
try:
|
||
|
|
pyrdata_id = cursor.fetchone()[0]
|
||
|
|
except Exception as e:
|
||
|
|
print(f"EXEPTION: {e}")
|
||
|
|
return pyrdata_id
|
||
|
|
|
||
|
|
def insert_block_data(
|
||
|
|
self,
|
||
|
|
img_id: int,
|
||
|
|
level: int,
|
||
|
|
tilex: int,
|
||
|
|
tiley: int,
|
||
|
|
x: int,
|
||
|
|
y: int,
|
||
|
|
x0: int,
|
||
|
|
y0: int,
|
||
|
|
w: int,
|
||
|
|
h: int,
|
||
|
|
block_data: np.ndarray
|
||
|
|
) -> int:
|
||
|
|
"""
|
||
|
|
Insert block data into the tilefeatures table.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
img_id (int): ID of the image.
|
||
|
|
level (int): Pyramid level.
|
||
|
|
tilex (int): Logical tile x-coordinate.
|
||
|
|
tiley (int): Logical tile y-coordinate.
|
||
|
|
x (int): Center x-coordinate (in original resolution).
|
||
|
|
y (int): Center y-coordinate (in original resolution).
|
||
|
|
x0 (int): Center x-coordinate (in down-sampled resolution).
|
||
|
|
y0 (int): Center y-coordinate (in down-sampled resolution).
|
||
|
|
w (int): Width of the tile.
|
||
|
|
h (int): Height of the tile.
|
||
|
|
block_data (np.ndarray): Tile data as a numpy array.
|
||
|
|
[histogram_data: NULL.]
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
int: The ID of the newly inserted tile record.
|
||
|
|
"""
|
||
|
|
query_str = """
|
||
|
|
INSERT INTO pyramiddata (
|
||
|
|
img_id, level, tilex, tiley, x, y, x0, y0, w, h, hash, block_data
|
||
|
|
)
|
||
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||
|
|
RETURNING pyrdata_id;
|
||
|
|
|
||
|
|
"""
|
||
|
|
hsh = uuid.uuid4()
|
||
|
|
with self._connection.get_cursor() as cursor:
|
||
|
|
cursor.execute(
|
||
|
|
query_str,
|
||
|
|
(
|
||
|
|
img_id,
|
||
|
|
level,
|
||
|
|
tilex,
|
||
|
|
tiley,
|
||
|
|
x,
|
||
|
|
y,
|
||
|
|
x0,
|
||
|
|
y0,
|
||
|
|
w,
|
||
|
|
h,
|
||
|
|
str(hsh),
|
||
|
|
block_data
|
||
|
|
)
|
||
|
|
)
|
||
|
|
pyrdata_id = cursor.fetchone()[0]
|
||
|
|
return pyrdata_id
|
||
|
|
|
||
|
|
def insert_tile_data(self, rows: List[Tuple]) -> None:
|
||
|
|
"""
|
||
|
|
Insert tile data into the pyramiddata table using batch insertion.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
rows (List[Tuple]): List of tuples containing tile data to insert.
|
||
|
|
"""
|
||
|
|
query_str = """
|
||
|
|
INSERT INTO pyramiddata (
|
||
|
|
img_id, level, tilex, tiley, x, y, x0, y0, w, h, hash, tile_data
|
||
|
|
)
|
||
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||
|
|
"""
|
||
|
|
|
||
|
|
with self._connection.cursor() as cursor:
|
||
|
|
# Use execute_batch for efficient batch insertion
|
||
|
|
print(f"Inserting {len(rows)} rows into pyramid {rows[:1]}")
|
||
|
|
extras.execute_batch(cursor, query_str, rows)
|
||
|
|
self._connection.commit()
|
||
|
|
|
||
|
|
def load_memmapped_histogram_data(self, file_path: str, rows=81):
|
||
|
|
"""
|
||
|
|
Load memory-mapped histogram data from a file.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
file_path (str): Path to the file containing the histogram data.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
np.ndarray: The loaded histogram data as a numpy array.
|
||
|
|
"""
|
||
|
|
return np.memmap(file_path, mode='r+', dtype='float32', shape=(rows,48))
|
||
|
|
|
||
|
|
def load_memmapped_tile_data(self, file_path: str):
|
||
|
|
"""
|
||
|
|
Load memory-mapped tile data from a file.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
file_path (str): Path to the file containing the tile data.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
np.ndarray: The loaded tile data as a numpy array.
|
||
|
|
"""
|
||
|
|
return np.memmap(file_path, mode='r+', dtype=np.uint16)
|
||
|
|
|
||
|
|
def load_memmapped_block_data(self, file_path: str):
|
||
|
|
"""
|
||
|
|
Load memory-mapped tile data from a file.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
file_path (str): Path to the file containing the tile data.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
np.ndarray: The loaded tile data as a numpy array.
|
||
|
|
"""
|
||
|
|
return np.memmap(file_path, mode='r+', dtype=np.uint16)
|
||
|
|
|
||
|
|
def get_image_by_id(self, img_id: int) -> Tuple:
|
||
|
|
"""
|
||
|
|
Retrieve an image record by its ID.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
img_id (int): ID of the image to retrieve.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
tuple: A tuple representing the image record.
|
||
|
|
"""
|
||
|
|
query_str = "SELECT * FROM images WHERE img_id = %s;"
|
||
|
|
with self._connection.cursor() as cursor:
|
||
|
|
cursor.execute(query_str, (img_id,))
|
||
|
|
return cursor.fetchone()
|
||
|
|
|
||
|
|
def get_pyramid_metadata_by_image_id(self, img_id: int) -> List[Tuple]:
|
||
|
|
"""
|
||
|
|
Retrieve all pyramid metadata records associated with an image.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
img_id (int): ID of the image.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
list: A list of tuples representing the pyramid metadata records.
|
||
|
|
"""
|
||
|
|
query_str = "SELECT * FROM pyramidmetadata WHERE img_id = %s;"
|
||
|
|
with self._connection.cursor() as cursor:
|
||
|
|
cursor.execute(query_str, (img_id,))
|
||
|
|
return cursor.fetchall()
|
||
|
|
|
||
|
|
def get_pyramid_metadata_by_id(self, pyramid_id: int) -> Tuple:
|
||
|
|
"""
|
||
|
|
Retrieve a pyramid metadata record by its ID.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
pyramid_id (int): ID of the pyramid metadata record.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
tuple: A tuple representing the pyramid metadata record.
|
||
|
|
"""
|
||
|
|
query_str = "SELECT * FROM pyramidmetadata WHERE pyramid_id = %s;"
|
||
|
|
with self._connection.cursor() as cursor:
|
||
|
|
cursor.execute(query_str, (pyramid_id,))
|
||
|
|
return cursor.fetchone()
|
||
|
|
|
||
|
|
def get_image_id_by_img_name(self, img_name: str) -> int:
|
||
|
|
"""
|
||
|
|
Retrieve the ID of an image by its name.
|
||
|
|
Args:
|
||
|
|
img_name (str): Name of the image file.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
int: The ID of the image, or None if not found.
|
||
|
|
"""
|
||
|
|
query_str = "SELECT img_id FROM avdb_image WHERE img_name = %s;"
|
||
|
|
with self._connection.cursor() as cursor:
|
||
|
|
cursor.execute(query_str, (img_name,))
|
||
|
|
result = cursor.fetchone()
|
||
|
|
return result[0] if result else None
|
||
|
|
|
||
|
|
def process_and_insert_histogram_data(
|
||
|
|
self,
|
||
|
|
img_id: int,
|
||
|
|
img_dims: Tuple[int, int],
|
||
|
|
level: int,
|
||
|
|
histogram_file: str,
|
||
|
|
grid_size: int = 9,
|
||
|
|
bin_size: int = 48
|
||
|
|
) -> None:
|
||
|
|
"""
|
||
|
|
Process and insert histogram data for a specific level of an image.
|
||
|
|
Args:
|
||
|
|
img_id (int): ID of the image.
|
||
|
|
img_dims (tuple): Dimensions of the image (width, height).
|
||
|
|
level (int): Pyramid level.
|
||
|
|
histogram_file (str): The memory-mapped histogram file.
|
||
|
|
grid_size (int): Size of the grid (e.g., 9 for 9x9 grid).
|
||
|
|
bin_size (int): Number of bins in the histogram (e.g., 48 for Lab histogram).
|
||
|
|
"""
|
||
|
|
if level<1:
|
||
|
|
raise ValueError("Level must be greater than 0")
|
||
|
|
# Calculate the downsampled resolution for this level
|
||
|
|
resolution = 2 ** level
|
||
|
|
|
||
|
|
# Load the memory-mapped histogram data
|
||
|
|
histogram_data = self.load_memmapped_histogram_data(histogram_file, grid_size**2)
|
||
|
|
|
||
|
|
# print(type(histogram_data))
|
||
|
|
|
||
|
|
print(f"histogram_data shape: {histogram_data.shape}")
|
||
|
|
|
||
|
|
img_w,img_h = img_dims
|
||
|
|
|
||
|
|
# print(list((histogram_data[0,:]).flatten()))
|
||
|
|
counter = 0
|
||
|
|
# Loop through each grid cell
|
||
|
|
for tilex in range(grid_size):
|
||
|
|
for tiley in range(grid_size):
|
||
|
|
# Calculate spatial coordinates (simplified for now)
|
||
|
|
# These calculations can be adjusted based on your specific requirements
|
||
|
|
x = tilex * (img_w // resolution)
|
||
|
|
y = tiley * (img_h // resolution)
|
||
|
|
x0 = tilex * (img_w // (resolution * grid_size ))
|
||
|
|
y0 = tiley * (img_h // (resolution * grid_size))
|
||
|
|
w = img_w // (resolution / 2)
|
||
|
|
h = img_h // (resolution / 2)
|
||
|
|
# Insert the histogram data into the database
|
||
|
|
# print(f"Inserting histogram data for tilex: {tilex}, tiley: {tiley}")
|
||
|
|
# print(f"x={x}, y={y}, x0={x0}, y0={y0}, w={w}, h={h}")
|
||
|
|
# print(type(list((histogram_data[counter,:]).flatten().tolist())[0]))
|
||
|
|
self.insert_histogram_data(
|
||
|
|
img_id=img_id,
|
||
|
|
level=level,
|
||
|
|
tilex=tilex,
|
||
|
|
tiley=tiley,
|
||
|
|
x=x,
|
||
|
|
y=y,
|
||
|
|
x0=x0,
|
||
|
|
y0=y0,
|
||
|
|
w=w,
|
||
|
|
h=h,
|
||
|
|
histogram_data=list((histogram_data[counter,:]).flatten().tolist())
|
||
|
|
)
|
||
|
|
counter += 1
|
||
|
|
|
||
|
|
def to_unsigned(self, signed_int):
|
||
|
|
return signed_int + (1 << 8) if signed_int < 0 else signed_int
|
||
|
|
|
||
|
|
def process_and_insert_tile_data_batched(
|
||
|
|
self,
|
||
|
|
img_id: int,
|
||
|
|
img_dims: Tuple[int, int],
|
||
|
|
level: int,
|
||
|
|
tile_file: str
|
||
|
|
) -> None:
|
||
|
|
"""
|
||
|
|
Process and insert tile data for a specific level of an image.
|
||
|
|
Args:
|
||
|
|
img_id (int): ID of the image.
|
||
|
|
img_dims (Tuple[int, int]): Dimensions of the image (width, height).
|
||
|
|
level (int): Pyramid level.
|
||
|
|
tile_file (str): The memory-mapped tile file.
|
||
|
|
grid_size (int): Size of the grid.
|
||
|
|
"""
|
||
|
|
# Calculate the downsampled resolution for this level
|
||
|
|
resolution = 2 ** level
|
||
|
|
img_w, img_h = img_dims
|
||
|
|
# Load the memory-mapped tile data
|
||
|
|
print(tile_file)
|
||
|
|
tile_data = self.load_memmapped_tile_data(tile_file)
|
||
|
|
|
||
|
|
print(f"img dims: {img_dims}")
|
||
|
|
print(f"tile data shape:{tile_data.shape}")
|
||
|
|
|
||
|
|
tilew = img_w // resolution
|
||
|
|
tileh = img_h // resolution
|
||
|
|
width_t = img_w // tilew
|
||
|
|
height_t = img_h // tileh
|
||
|
|
|
||
|
|
grid_size = 1
|
||
|
|
|
||
|
|
def gen_tiles():
|
||
|
|
counter = 0
|
||
|
|
# Loop through each tile
|
||
|
|
for tiley in range(tileh):
|
||
|
|
for tilex in range(tilew):
|
||
|
|
|
||
|
|
x0 = tilex * width_t
|
||
|
|
y0 = tiley * height_t
|
||
|
|
w = grid_size
|
||
|
|
h = 1
|
||
|
|
|
||
|
|
# print(f"{counter} - {level} - {tilex} - {tiley} - {tilew} - {tileh} - {width_t} - {height_t} - {x0} - {y0} - {w} - {h} -- {tile_data[(counter * 3):((counter+1) * 3)]}")
|
||
|
|
# Insert the tile data into the database
|
||
|
|
try:
|
||
|
|
tiledata = list(
|
||
|
|
(
|
||
|
|
np.r_[
|
||
|
|
tile_data[
|
||
|
|
(counter * 3):
|
||
|
|
((counter+1) * 3)
|
||
|
|
]
|
||
|
|
]
|
||
|
|
).flatten().tolist()
|
||
|
|
)
|
||
|
|
counter += 1
|
||
|
|
yield (
|
||
|
|
img_id,
|
||
|
|
level,
|
||
|
|
tilex,
|
||
|
|
tiley,
|
||
|
|
width_t,
|
||
|
|
height_t,
|
||
|
|
x0,
|
||
|
|
y0,
|
||
|
|
w,
|
||
|
|
h,
|
||
|
|
str(uuid.uuid4()),
|
||
|
|
list(map(self.to_unsigned,tiledata))
|
||
|
|
)
|
||
|
|
except Exception as e:
|
||
|
|
print(f"ERROR: {e}")
|
||
|
|
|
||
|
|
all_for_insertion = list(gen_tiles())
|
||
|
|
print(f"Inserting {len(all_for_insertion)} tiles")
|
||
|
|
|
||
|
|
self.insert_tile_data(all_for_insertion)
|
||
|
|
|
||
|
|
|
||
|
|
def process_and_insert_block_data(
|
||
|
|
self,
|
||
|
|
img_id: int,
|
||
|
|
img_dims: Tuple[int, int],
|
||
|
|
level: int,
|
||
|
|
block_file: str,
|
||
|
|
grid_size: int = 9
|
||
|
|
) -> None:
|
||
|
|
"""
|
||
|
|
Process and insert block data for a specific level of an image.
|
||
|
|
Args:
|
||
|
|
img_id (int): ID of the image.
|
||
|
|
img_dims (Tuple[int, int]): Dimensions of the image (width, height).
|
||
|
|
level (int): Pyramid level.
|
||
|
|
block_file (str): The memory-mapped block file.
|
||
|
|
grid_size (int): Size of the grid.
|
||
|
|
"""
|
||
|
|
# Calculate the downsampled resolution for this level
|
||
|
|
resolution = 2 ** level
|
||
|
|
img_w, img_h = img_dims
|
||
|
|
|
||
|
|
# if level == 6:
|
||
|
|
# row_size = 9
|
||
|
|
# elif level == 7:
|
||
|
|
# row_size = 5
|
||
|
|
# else:
|
||
|
|
|
||
|
|
if level not in (6, 7):
|
||
|
|
raise ValueError(f"Unsupported level ({level}). Level must be 6 or 7.")
|
||
|
|
|
||
|
|
# Load the memory-mapped block data
|
||
|
|
block_data = self.load_memmapped_block_data(block_file)
|
||
|
|
|
||
|
|
# print(f"img dims: {img_dims}")
|
||
|
|
# print(f"block data shape:{block_data.shape}")
|
||
|
|
|
||
|
|
tilew = img_w // resolution
|
||
|
|
tileh = img_h // resolution
|
||
|
|
width_t = img_w // tilew
|
||
|
|
height_t = img_h // tileh
|
||
|
|
|
||
|
|
# print(f"tilew: {tilew}, tileh: {tileh}, width_t: {width_t}, height_t: {height_t}")
|
||
|
|
|
||
|
|
counter = 0
|
||
|
|
# Loop through each block
|
||
|
|
for tilex in range(tilew-2):
|
||
|
|
for tiley in range(tileh-2):
|
||
|
|
|
||
|
|
x0 = tilex * width_t
|
||
|
|
y0 = tiley * height_t
|
||
|
|
w = grid_size
|
||
|
|
h = 1
|
||
|
|
|
||
|
|
# print(f"{counter} - {level} - {tilex} - {tiley} - {tilew} - {tileh} - {width_t} - {height_t} - {x0} - {y0} - {w} - {h}")
|
||
|
|
# Insert the block data into the database
|
||
|
|
# print(f"{counter * grid_size * 3} - {(counter+1) * grid_size * 3}")
|
||
|
|
|
||
|
|
try:
|
||
|
|
self.insert_block_data(
|
||
|
|
img_id=img_id,
|
||
|
|
level=level,
|
||
|
|
tilex=tilex,
|
||
|
|
tiley=tiley,
|
||
|
|
x=w,
|
||
|
|
y=h,
|
||
|
|
x0=x0,
|
||
|
|
y0=y0,
|
||
|
|
w=w,
|
||
|
|
h=h,
|
||
|
|
block_data=list(
|
||
|
|
(
|
||
|
|
np.r_[
|
||
|
|
block_data[
|
||
|
|
(counter * grid_size * 3):
|
||
|
|
((counter+1) * grid_size * 3)
|
||
|
|
]
|
||
|
|
# np.zeros((9 - grid_size) * 3)
|
||
|
|
]
|
||
|
|
).flatten().tolist()
|
||
|
|
)
|
||
|
|
)
|
||
|
|
except Exception as e:
|
||
|
|
print(f"ERROR: {e}")
|
||
|
|
pass
|
||
|
|
counter += 1
|
||
|
|
|
||
|
|
def extract_image_base(self, fullpath: str) -> str:
|
||
|
|
|
||
|
|
term = r'.*(IMG_\d{4}|TESTIMG).*'
|
||
|
|
m = re.match(term, fullpath)
|
||
|
|
if m is not None:
|
||
|
|
tkn = m.group(1)
|
||
|
|
return f"img/{tkn}/{tkn}.jpeg", tkn
|
||
|
|
raise ValueError(f"Could not extract image base from {fullpath}")
|
||
|
|
|
||
|
|
def process_image_analysis(
|
||
|
|
self,
|
||
|
|
img_path_in: str,
|
||
|
|
max_level: int = 8
|
||
|
|
) -> None:
|
||
|
|
"""
|
||
|
|
Process and insert all analysis data for an image across multiple levels.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
img_id (int): ID of the image.
|
||
|
|
img_path (str): Full path.
|
||
|
|
max_level (int): max exponent to pyr down splits
|
||
|
|
"""
|
||
|
|
img_path, img_tkn = self.extract_image_base(img_path_in)
|
||
|
|
print(img_path)
|
||
|
|
# assumes image has been inserted into image table
|
||
|
|
img_id = self.get_image_id_by_img_name(os.path.basename(img_path))
|
||
|
|
|
||
|
|
print(f"IMAGE ID: {img_id}")
|
||
|
|
|
||
|
|
# insert image metadata
|
||
|
|
if not os.path.exists(img_path):
|
||
|
|
raise FileNotFoundError(f"{img_path} does not exist")
|
||
|
|
|
||
|
|
img = cv.imread(img_path)
|
||
|
|
|
||
|
|
width = img.shape[1]
|
||
|
|
height = img.shape[0]
|
||
|
|
|
||
|
|
print(f"Processing image {img_path} {width}x{height} {img_path}")
|
||
|
|
|
||
|
|
for level in range(max_level):
|
||
|
|
print(LEVELS_CONFIG[level])
|
||
|
|
|
||
|
|
if (LEVELS_CONFIG[level]["gridsplit"]) is not None:
|
||
|
|
data_path = f"{os.path.dirname(img_path)}/{img_path}.histos.mmap"
|
||
|
|
grid_size = LEVELS_CONFIG[level]["gridsplit"] + 1
|
||
|
|
# Process histogram data for this level
|
||
|
|
self.process_and_insert_histogram_data(
|
||
|
|
img_id=img_id,
|
||
|
|
img_dims=(width, height),
|
||
|
|
level=level,
|
||
|
|
histogram_file=data_path,
|
||
|
|
grid_size=grid_size
|
||
|
|
)
|
||
|
|
if (LEVELS_CONFIG[level]["tiles"]):
|
||
|
|
data_path = f"img/{img_tkn}/{img_tkn}.lab.pyr_{level}.jpeg.tiles.mmap"
|
||
|
|
print(data_path)
|
||
|
|
print("INSERTING TILE DATA")
|
||
|
|
# Process tile data for this level
|
||
|
|
self.process_and_insert_tile_data_batched(
|
||
|
|
img_id=img_id,
|
||
|
|
img_dims=(width, height),
|
||
|
|
level=level,
|
||
|
|
tile_file=data_path
|
||
|
|
)
|
||
|
|
|
||
|
|
if (LEVELS_CONFIG[level]["targetblocks"]) is not None:
|
||
|
|
data_path = f"{os.path.dirname(img_path)}/{img_path}.blocks.mmap"
|
||
|
|
print("INSERTING BLOCK DATA")
|
||
|
|
# Process block data for this level
|
||
|
|
self.process_and_insert_block_data(
|
||
|
|
img_id=img_id,
|
||
|
|
img_dims=(width, height),
|
||
|
|
level=level,
|
||
|
|
block_file=data_path
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
with DBConnection('testdb').get_connection() as db_conn:
|
||
|
|
db_ops = DBOps(db_conn)
|
||
|
|
db_ops.process_image_analysis('home/kfl/dev/git/avdb-py-v1/img/TESTIMG/TESTIMG.jpeg')
|
||
|
|
|