|
import sys |
|
sys.path.append('Depth-Anything-V2') |
|
|
|
import cv2 |
|
import torch |
|
import matplotlib.pyplot as plt |
|
import numpy as np |
|
from PIL import Image |
|
from depth_anything_v2.dpt import DepthAnythingV2 |
|
from pathlib import Path |
|
from tqdm.auto import tqdm |
|
import argparse |
|
|
|
|
|
def parse_args(): |
|
parser = argparse.ArgumentParser(description='Generate depth and normal maps from images') |
|
parser.add_argument('--source_root', type=str, default='test_dir', |
|
help='Root directory containing the images') |
|
parser.add_argument('--model_path', type=str, |
|
default='depth_anything_v2_vitl.pth', |
|
help='Path to the depth model checkpoint') |
|
return parser.parse_args() |
|
|
|
|
|
def generate_depth_maps(source_root, model_path): |
|
source_root = Path(source_root) |
|
origin = source_root / 'origin' |
|
to_depth_list = [origin] |
|
|
|
model = DepthAnythingV2(encoder='vitl', features=256, out_channels=[256, 512, 1024, 1024]).cuda() |
|
model.load_state_dict(torch.load(model_path, map_location='cpu')) |
|
model.eval() |
|
|
|
depth_path = source_root / 'depth' |
|
depth_path.mkdir(parents=True, exist_ok=True) |
|
|
|
with torch.inference_mode(): |
|
for to_depth_item in to_depth_list: |
|
folder_name = to_depth_item.stem |
|
dst_path = depth_path |
|
|
|
dst_path.mkdir(parents=True, exist_ok=True) |
|
|
|
bar = tqdm(to_depth_item.glob('*')) |
|
|
|
for image_path in bar: |
|
try: |
|
raw_img = cv2.imread(str(image_path)) |
|
depth = model.infer_image(raw_img) |
|
|
|
depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255.0 |
|
depth = depth.astype(np.uint8) |
|
|
|
np.save(f'{dst_path}/{image_path.stem}.npy', depth) |
|
|
|
except Exception as e: |
|
print(e) |
|
continue |
|
|
|
return depth_path |
|
|
|
|
|
def calculate_normal_map(img_path: Path, ksize=5): |
|
|
|
depth = np.load(img_path).astype(np.float32) |
|
|
|
|
|
dx = cv2.Sobel(depth, cv2.CV_32F, 1, 0, ksize=ksize) |
|
dy = cv2.Sobel(depth, cv2.CV_32F, 0, 1, ksize=ksize) |
|
|
|
|
|
dz = np.ones_like(dx) * -1 |
|
|
|
|
|
normals = np.stack((dx, dy, dz), axis=-1) |
|
|
|
|
|
norm = np.linalg.norm(normals, axis=-1, keepdims=True) |
|
normals /= (norm + 1e-6) |
|
|
|
|
|
normal_map = (normals + 1) / 2 * 255 |
|
normal_map = normal_map.astype("uint8") |
|
|
|
normal_map = normal_map.transpose(2, 0, 1) |
|
|
|
return normal_map |
|
|
|
|
|
def generate_normal_maps(source_root, ksize=5): |
|
source_root = Path(source_root) |
|
depth_root = source_root / 'depth' |
|
normal_root = source_root / 'normal' |
|
normal_root.mkdir(parents=True, exist_ok=True) |
|
|
|
bar = tqdm(list(depth_root.glob('*.npy'))) |
|
|
|
for depth_img_path in bar: |
|
img_name = depth_img_path.name |
|
|
|
normal_map = calculate_normal_map(depth_img_path, ksize=ksize) |
|
|
|
np.save(f'{normal_root}/{img_name}', normal_map) |
|
|
|
|
|
def main(): |
|
args = parse_args() |
|
|
|
print(f"Generating depth maps from images in {args.source_root}") |
|
depth_path = generate_depth_maps(args.source_root, args.model_path) |
|
|
|
print(f"Generating normal maps from depth maps") |
|
generate_normal_maps(args.source_root) |
|
|
|
print("Processing complete!") |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |