diff --git a/.gitignore b/.gitignore
index 558ed45..3cbb092 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,10 @@
*.sh
log_test/
result_1024
-
+env-dpr
+result/
+result*
+__pycache__
+.idea
+res.jpg
+.vscode
\ No newline at end of file
diff --git a/README.md b/README.md
index 9f8de56..8d5d1ae 100644
--- a/README.md
+++ b/README.md
@@ -19,17 +19,198 @@ Hao Zhou, Sunil Hadap, Kalyan Sunkavalli, David W. Jacobs. In ICCV, 2019
pytorch >= 1.0.0
-opencv >= 4.0.0
-shtools: https://shtools.oca.eu/shtools/ (optional)
+- [Deep Single-Image Portrait Relighting](#deep-single-image-portrait-relighting) + - [Overview](#overview) + - [Notes](#notes) + - [Project Structure](#project-structure) + - [Requirements](#requirements) + - [Setup Instructions](#setup-instructions) + - [Brightness Configuration File](#brightness-configuration-file) + - [Running the Project](#running-the-project) + - [Data Preparation](#data-preparation) + - [Citation](#citation) +--- +# Overview +This project is an implementation of the paper "Deep Single-Image Portrait Relighting" presented at ICCV 2019. Its core goal is to perform relighting on single portrait images using deep learning: given an input portrait and a target lighting configuration, the model can re-render the same face under completely new illumination conditions. The method is fundamentally based on intrinsic image decomposition, where the network learns to separate an input image into its physically meaningful components—albedo (surface reflectance), geometry (represented by a depth map or surface normal vectors), and scene lighting. By disentangling these factors and then replacing the estimated lighting component with a desired target profile, the system renders the final output through a data-driven pipeline rooted in classic image formation models, enabling precise and controllable illumination effects. + +From a technical standpoint, the architecture relies on a U-Net with an Hourglass structure that preserves spatial resolution while extracting features. A key design choice is the use of second-order Spherical Harmonics (SH) for lighting representation, employing 9 coefficients: one for ambient light, three for directional lighting along the coordinate axes, and five for higher-frequency details such as soft shadows on curved facial surfaces. This compact yet physically grounded representation makes illumination manipulation both efficient and interpretable. The codebase supports processing images at 512×512 and 1024×1024 resolutions and depends on the shtools library for SH-related functions. It also provides utilities to convert between different SH coordinate conventions (e.g., bip2017, sfsNet) and the one adopted here. Training data is organized into separate train, validation, and test file lists, while the rendering-based data generation pipeline resides in a separate repository. ### Notes -We include an example image and seven example lightings in data. Note that different methods may have different coordinate system for Spherical Harmonics (SH), you may need to change the coordiante system if you use SH lighting from other sources. The coordinate system of our method is in accordance with shtools, we provide a function utils_normal.py in utils to help you tansfer the coordinate system from [bip2017](https://gravis.dmi.unibas.ch/PMM/data/bip/) and [sfsNet](https://senguptaumd.github.io/SfSNet/) to our coordinate system. To use utils_normal.py you need to install shtools. The code is for research purpose only. + +- We provide one example input image and seven example lighting configurations in the `data` directory. + +- Different methods may adopt different coordinate systems for Spherical Harmonics (SH). + If you use SH lighting from external sources, you may need to convert the coordinate system accordingly. + +- The coordinate system used in this project follows the convention of **shtools**. + +- We provide a utility script `utils_normal.py` (located in the `utils` directory) to help convert SH coefficients from: + - [bip2017](https://gravis.dmi.unibas.ch/PMM/data/bip/) + - [sfsNet](https://senguptaumd.github.io/SfSNet/) + into the coordinate system used in this project. + +- To use `utils_normal.py`, you must install **shtools**. + +- This code is provided for **research purposes only**. + +--- +# Project Structure +```text +. +├── candidiate_config +│ ├── candidate1 +│ │ ├── rotate_light_04_0.txt +│ │ ├── rotate_light_04.txt +│ │ └── rotate_light_06.txt +│ ├── candidate2 +│ │ ├── rotate_light_03_0.txt +│ │ ├── rotate_light_03_1.txt +│ │ ├── rotate_light_03.txt +│ │ ├── rotate_light_04_0.txt +│ │ └── rotate_light_04.txt +│ └── candidate3 +│ ├── rotate_light_02.txt +│ ├── rotate_light_03.txt +│ ├── rotate_light_04_0.txt +│ └── rotate_light_04.txt +├── data +│ ├── example_light +│ │ ├── rotate_light_00.txt +│ │ ├── rotate_light_01.txt +│ │ ├── rotate_light_02.txt +│ │ ├── rotate_light_03.txt +│ │ ├── rotate_light_04.txt +│ │ ├── rotate_light_05.txt +│ │ └── rotate_light_06.txt +│ ├── example_light_original +│ │ ├── rotate_light_00.txt +│ │ ├── rotate_light_01.txt +│ │ ├── rotate_light_02.txt +│ │ ├── rotate_light_03.txt +│ │ ├── rotate_light_04.txt +│ │ ├── rotate_light_05.txt +│ │ └── rotate_light_06.txt +│ ├── obama.jpg +│ ├── test.lst +│ ├── train.lst +│ └── val.lst +├── model +│ ├── defineHourglass_1024_gray_skip_matchFeature.py +│ └── defineHourglass_512_gray_skip.py +├── obama.jpg +├── README.md +├── requirment.txt +├── result +│ ├── light_00.png +│ ├── light_01.png +│ ├── light_02.png +│ ├── light_03.png +│ ├── light_04.png +│ ├── light_05.png +│ ├── light_06.png +│ ├── obama_00.jpg +│ ├── obama_01.jpg +│ ├── obama_02.jpg +│ ├── obama_03.jpg +│ ├── obama_04.jpg +│ ├── obama_05.jpg +│ └── obama_06.jpg +├── test +│ └── test_light_condition.py +├── trained_model +│ ├── trained_model_03.t7 +│ └── trained_model_1024_03.t7 +└── utils + ├── testNetwork_demo_1024.py + ├── testNetwork_demo_512.py + ├── utils_normal.py + ├── utils_SH.py + └── utils_shtools.py +``` + +# Requirements + +To run this project, please make sure the following prerequisites are met: + +- **Python 3.10** +- All required packages listed in `requirement.txt` + +We strongly recommend using a virtual environment to avoid dependency conflicts. + +## Setup Instructions + +1. Create and activate a virtual environment: +```bash +python3.10 -m venv dpr-env +source dpr-env/bin/activate # On Linux / macOS +# dpr-env\Scripts\activate # On Windows +``` +2. install python packages +```bash +pip install --upgrade pip +pip install -r requirement.txt +``` +--- + +# Brightness Configuration File + +- The directory `data/example_light_original` contains multiple lighting configuration files. + Each configuration defines a specific lighting condition, including variations in illumination angle and light intensity. + +- These configuration files are used to simulate how the portrait appears under different lighting directions and strengths. + +- Detailed explanations of the configuration file parameters are provided in the following section. + +This configuration file contains settings that include 9 coefficients related to lighting. + +```text +1.084125496282453138e+00 +-4.642676300617166185e-01 +2.837846795150648915e-02 +6.765292733937575687e-01 +-3.594067725393816914e-01 +4.790996460111427574e-02 +-2.280054643781863066e-01 +-8.125983081159608712e-02 +2.881082012687687932e-01 +``` +- The **first coefficient** represents the ambient light. This value determines the overall base brightness of the image regardless of direction. +- The **next 3 coefficients** represent directional linear lighting along the x, y, and z axes respectively. These values specify the main light direction (left/right, up/down, front/back) shining onto the face. + - **Light along X axis**: Controls the directional light intensity along the X axis (left ↔ right). + - **Light along Y axis**: Controls the directional light intensity along the Y axis (up ↔ down). + - **Light along Z axis**: Controls the directional light intensity along the Z axis (front ↔ back). + +- The **last 5 coefficients** represent complex lighting details used for more accurate simulation of light diffusion and softer shadows on curved surfaces (such as a human face). + - **Coefficient dependent on x·y**: Represents lighting variations influenced by the interaction between the X and Y axes. + - **Coefficient dependent on y·z**: Represents lighting variations influenced by the interaction between the Y and Z axes. + - **Coefficient dependent on 3z² − 1**: Controls spherical lighting deformation related to the Z‑axis curvature component. + - **Coefficient dependent on x·z**: Represents lighting variations influenced by the interaction between the X and Z axes. + - **Coefficient dependent on x² − y²**: Describes lighting differences caused by the relative contribution of the X and Y axes. + +These coefficients work together to create a realistic lighting effect in the rendered image. + +--- +# Running the Project + +- In the project repository, a set of **unit tests** has been provided that can be used to generate example outputs. + +- These tests are located in the corresponding test directory of the project. + +- The main methods for producing output are: + - `test_network_512_demo` + - `test_network_1024_demo` + +- These two methods demonstrate how to run the model and obtain relit portrait results. + +- The other test methods in the directory provide additional functionality and examples. + You can understand their usage by reading the code. + +- For generating initial outputs and testing the pipeline, running the two demo methods above is sufficient. + +--- ### Data Preparation We publish the code for data preparation, please find it in (https://github.com/zhhoper/RI_render_DPR). diff --git a/candidiate_config/candidate1/rotate_light_04.txt b/candidiate_config/candidate1/rotate_light_04.txt new file mode 100644 index 0000000..ef1becf --- /dev/null +++ b/candidiate_config/candidate1/rotate_light_04.txt @@ -0,0 +1,9 @@ +0.27040471416103395 +-0.46426763006171867243 +-0.31910316690564172193 +-0.59721885776719108030 +-0.397097723888441 +-0.9453971324343751 +-0.47237695706463145 +0.024516914229173237 +-0.2663783549655807 \ No newline at end of file diff --git a/candidiate_config/candidate1/rotate_light_04_0.txt b/candidiate_config/candidate1/rotate_light_04_0.txt new file mode 100644 index 0000000..6a43a16 --- /dev/null +++ b/candidiate_config/candidate1/rotate_light_04_0.txt @@ -0,0 +1,9 @@ +0.7599764749674436 +-0.46426763006171867243 +-0.31910316690564172193 +-0.59721885776719108030 +0.5573975266935798 +0.5001595651885822 +0.7140101606482576 +0.380439487506566 +0.09412198842435937 \ No newline at end of file diff --git a/candidiate_config/candidate1/rotate_light_06.txt b/candidiate_config/candidate1/rotate_light_06.txt new file mode 100644 index 0000000..3f8e045 --- /dev/null +++ b/candidiate_config/candidate1/rotate_light_06.txt @@ -0,0 +1,9 @@ +0.6767738540804545 +-0.46426763006171695158 +-0.51123819939032077997 +0.44399628228860482659 +-0.8949978210034468 +-0.5563591448349721 +-0.04249981903504674 +-0.1447678371507346 +0.016304285486612224 \ No newline at end of file diff --git a/candidiate_config/candidate2/rotate_light_03.txt b/candidiate_config/candidate2/rotate_light_03.txt new file mode 100644 index 0000000..43646b7 --- /dev/null +++ b/candidiate_config/candidate2/rotate_light_03.txt @@ -0,0 +1,9 @@ +0.13232263947052458 +-0.46426763006171867243 +0.26796693461949411263 +-0.62184476933764609718 +0.3971838831057054 +0.06932086334888465 +0.10502199133045376 +0.2126737014583967 +0.9105873950786283 \ No newline at end of file diff --git a/candidiate_config/candidate2/rotate_light_03_0.txt b/candidiate_config/candidate2/rotate_light_03_0.txt new file mode 100644 index 0000000..f5f1255 --- /dev/null +++ b/candidiate_config/candidate2/rotate_light_03_0.txt @@ -0,0 +1,9 @@ +0.08480793042881807 +-0.46426763006171867243 +0.26796693461949411263 +-0.62184476933764609718 +0.7620709851296886 +0.16208580389706828 +0.4707111097148129 +0.11499643536007365 +0.45468509701365134 \ No newline at end of file diff --git a/candidiate_config/candidate2/rotate_light_03_1.txt b/candidiate_config/candidate2/rotate_light_03_1.txt new file mode 100644 index 0000000..abb21cb --- /dev/null +++ b/candidiate_config/candidate2/rotate_light_03_1.txt @@ -0,0 +1,9 @@ +0.1962672986198406 +-0.46426763006171867243 +0.26796693461949411263 +-0.62184476933764609718 +0.9644050707577712 +0.5356968951299693 +0.30490039971179483 +0.4148029522455058 +0.9945177431726548 \ No newline at end of file diff --git a/candidiate_config/candidate2/rotate_light_04.txt b/candidiate_config/candidate2/rotate_light_04.txt new file mode 100644 index 0000000..fca66ef --- /dev/null +++ b/candidiate_config/candidate2/rotate_light_04.txt @@ -0,0 +1,9 @@ +0.13644282027529087 +-0.46426763006171867243 +-0.31910316690564172193 +-0.59721885776719108030 +0.5937625728758151 +0.2537910536841331 +0.09708440767577975 +0.6908752097806585 +0.9128589362594567 \ No newline at end of file diff --git a/candidiate_config/candidate2/rotate_light_04_0.txt b/candidiate_config/candidate2/rotate_light_04_0.txt new file mode 100644 index 0000000..ad49eb1 --- /dev/null +++ b/candidiate_config/candidate2/rotate_light_04_0.txt @@ -0,0 +1,9 @@ +0.04725591345770108 +-0.46426763006171867243 +-0.31910316690564172193 +-0.59721885776719108030 +0.32721833828615376 +0.2651040031674805 +0.16997635830083313 +0.8322291732242509 +0.6038195991231404 \ No newline at end of file diff --git a/candidiate_config/candidate3/rotate_light_02.txt b/candidiate_config/candidate3/rotate_light_02.txt new file mode 100644 index 0000000..37111f7 --- /dev/null +++ b/candidiate_config/candidate3/rotate_light_02.txt @@ -0,0 +1,9 @@ +-0.06418672177194007 +-0.46426763006171795078 +0.65325246884684284865 +-0.17820888627524578141 +0.5232245651178373 +0.403902811802879 +0.44893903369868327 +0.8274382240234986 +0.765513739352323 \ No newline at end of file diff --git a/candidiate_config/candidate3/rotate_light_03.txt b/candidiate_config/candidate3/rotate_light_03.txt new file mode 100644 index 0000000..6efd12f --- /dev/null +++ b/candidiate_config/candidate3/rotate_light_03.txt @@ -0,0 +1,9 @@ +-0.44333633966552344 +-0.46426763006171867243 +0.26796693461949411263 +-0.62184476933764609718 +0.6470974817487151 +0.06988406362642641 +0.826308199976985 +0.5886195484274779 +0.49124674739238094 \ No newline at end of file diff --git a/candidiate_config/candidate3/rotate_light_04.txt b/candidiate_config/candidate3/rotate_light_04.txt new file mode 100644 index 0000000..8120461 --- /dev/null +++ b/candidiate_config/candidate3/rotate_light_04.txt @@ -0,0 +1,9 @@ +0.6225771867250876 +-0.46426763006171867243 +-0.31910316690564172193 +-0.59721885776719108030 +0.611293056201971 +0.13495867234579872 +0.7831822217344969 +0.9466877512278259 +0.7823907396310225 \ No newline at end of file diff --git a/candidiate_config/candidate3/rotate_light_04_0.txt b/candidiate_config/candidate3/rotate_light_04_0.txt new file mode 100644 index 0000000..b315f6a --- /dev/null +++ b/candidiate_config/candidate3/rotate_light_04_0.txt @@ -0,0 +1,9 @@ +0.3395404471917278 +-0.46426763006171867243 +-0.31910316690564172193 +-0.59721885776719108030 +0.22729003974963624 +0.9256625956590697 +0.9071189187796489 +0.34868353659096296 +0.10067127449200142 \ No newline at end of file diff --git a/data/example_light/rotate_light_00.txt b/data/example_light/rotate_light_00.txt index be96d18..adb708e 100644 --- a/data/example_light/rotate_light_00.txt +++ b/data/example_light/rotate_light_00.txt @@ -6,4 +6,4 @@ 4.790996460111427574e-02 -2.280054643781863066e-01 -8.125983081159608712e-02 -2.881082012687687932e-01 +2.881082012687687932e-01 \ No newline at end of file diff --git a/data/example_light/rotate_light_01.txt b/data/example_light/rotate_light_01.txt index 5772db6..e076ea0 100644 --- a/data/example_light/rotate_light_01.txt +++ b/data/example_light/rotate_light_01.txt @@ -1,9 +1,9 @@ -1.084125496282453138e+00 +0.000000000000000000e+00 -4.642676300617170626e-01 5.466255701105990905e-01 3.996219229512094628e-01 --2.615439760463462715e-01 --2.511241554473071513e-01 -6.495694866016435420e-02 -3.510322039081858470e-01 -1.189662732386344152e-01 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 \ No newline at end of file diff --git a/data/example_light/rotate_light_02.txt b/data/example_light/rotate_light_02.txt index 41b1e9f..2848f8b 100644 --- a/data/example_light/rotate_light_02.txt +++ b/data/example_light/rotate_light_02.txt @@ -1,9 +1,9 @@ -1.084125496282453138e+00 +0.000000000000000000e+00 -4.642676300617179508e-01 6.532524688468428486e-01 -1.782088862752457814e-01 -3.326676893441832261e-02 --3.610566644446819295e-01 -3.647561777790956361e-01 --7.496419691318900735e-02 --5.412289239602386531e-02 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 diff --git a/data/example_light/rotate_light_03.txt b/data/example_light/rotate_light_03.txt index 533ebd8..f7f7e9c 100644 --- a/data/example_light/rotate_light_03.txt +++ b/data/example_light/rotate_light_03.txt @@ -1,9 +1,9 @@ -1.084125496282453138e+00 +0.000000000000000000e+00 -4.642676300617186724e-01 2.679669346194941126e-01 -6.218447693376460972e-01 -3.030269583891490037e-01 --1.991061409014726058e-01 --6.162944418511027977e-02 --3.176699976873690878e-01 -1.920509612235956343e-01 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 \ No newline at end of file diff --git a/data/example_light/rotate_light_04.txt b/data/example_light/rotate_light_04.txt index 05f783c..3e76684 100644 --- a/data/example_light/rotate_light_04.txt +++ b/data/example_light/rotate_light_04.txt @@ -1,9 +1,9 @@ -1.084125496282453138e+00 +0.000000000000000000e+00 -4.642676300617186724e-01 -3.191031669056417219e-01 -5.972188577671910803e-01 -3.446016675533919993e-01 -1.127753677656503223e-01 --1.716692196540034188e-01 -2.163406460637767315e-01 -2.555824552121269688e-01 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 \ No newline at end of file diff --git a/data/example_light/rotate_light_05.txt b/data/example_light/rotate_light_05.txt index 4c4d3fc..e263354 100644 --- a/data/example_light/rotate_light_05.txt +++ b/data/example_light/rotate_light_05.txt @@ -1,9 +1,9 @@ -1.084125496282453138e+00 +0.000000000000000000e+00 -4.642676300617178398e-01 -6.658820752324799974e-01 -1.228749652534838893e-01 -1.266842924569576145e-01 -3.397347243069742673e-01 -3.036887095295650041e-01 -2.213893524577207617e-01 --1.886557316342868038e-02 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 \ No newline at end of file diff --git a/data/example_light/rotate_light_06.txt b/data/example_light/rotate_light_06.txt index bbb04fb..be68171 100644 --- a/data/example_light/rotate_light_06.txt +++ b/data/example_light/rotate_light_06.txt @@ -1,9 +1,9 @@ -1.084125496282453138e+00 +0.000000000000000000e+00 -4.642676300617169516e-01 -5.112381993903207800e-01 4.439962822886048266e-01 --1.866289387481862572e-01 -3.108669041197227867e-01 -2.021743042675238355e-01 --3.148681770175290051e-01 -3.974379604123656762e-02 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 +0.000000000000000000e+00 \ No newline at end of file diff --git a/data/example_light_original/rotate_light_00.txt b/data/example_light_original/rotate_light_00.txt new file mode 100644 index 0000000..adb708e --- /dev/null +++ b/data/example_light_original/rotate_light_00.txt @@ -0,0 +1,9 @@ +1.084125496282453138e+00 +-4.642676300617166185e-01 +2.837846795150648915e-02 +6.765292733937575687e-01 +-3.594067725393816914e-01 +4.790996460111427574e-02 +-2.280054643781863066e-01 +-8.125983081159608712e-02 +2.881082012687687932e-01 \ No newline at end of file diff --git a/data/example_light_original/rotate_light_01.txt b/data/example_light_original/rotate_light_01.txt new file mode 100644 index 0000000..2cf88d1 --- /dev/null +++ b/data/example_light_original/rotate_light_01.txt @@ -0,0 +1,9 @@ +1.084125496282453138e+00 +-4.642676300617170626e-01 +5.466255701105990905e-01 +3.996219229512094628e-01 +-2.615439760463462715e-01 +-2.511241554473071513e-01 +6.495694866016435420e-02 +3.510322039081858470e-01 +1.189662732386344152e-01 \ No newline at end of file diff --git a/data/example_light_original/rotate_light_02.txt b/data/example_light_original/rotate_light_02.txt new file mode 100644 index 0000000..9f9f541 --- /dev/null +++ b/data/example_light_original/rotate_light_02.txt @@ -0,0 +1,9 @@ +1.084125496282453138e+00 +-4.642676300617179508e-01 +6.532524688468428486e-01 +-1.782088862752457814e-01 +3.326676893441832261e-02 +-3.610566644446819295e-01 +3.647561777790956361e-01 +-7.496419691318900735e-02 +-5.412289239602386531e-02 \ No newline at end of file diff --git a/data/example_light_original/rotate_light_03.txt b/data/example_light_original/rotate_light_03.txt new file mode 100644 index 0000000..533ebd8 --- /dev/null +++ b/data/example_light_original/rotate_light_03.txt @@ -0,0 +1,9 @@ +1.084125496282453138e+00 +-4.642676300617186724e-01 +2.679669346194941126e-01 +-6.218447693376460972e-01 +3.030269583891490037e-01 +-1.991061409014726058e-01 +-6.162944418511027977e-02 +-3.176699976873690878e-01 +1.920509612235956343e-01 diff --git a/data/example_light_original/rotate_light_04.txt b/data/example_light_original/rotate_light_04.txt new file mode 100644 index 0000000..c4b8520 --- /dev/null +++ b/data/example_light_original/rotate_light_04.txt @@ -0,0 +1,9 @@ +1.084125496282453138e+00 +-4.642676300617186724e-01 +-3.191031669056417219e-01 +-5.972188577671910803e-01 +3.446016675533919993e-01 +1.127753677656503223e-01 +-1.716692196540034188e-01 +2.163406460637767315e-01 +2.555824552121269688e-01 \ No newline at end of file diff --git a/data/example_light_original/rotate_light_05.txt b/data/example_light_original/rotate_light_05.txt new file mode 100644 index 0000000..06812c8 --- /dev/null +++ b/data/example_light_original/rotate_light_05.txt @@ -0,0 +1,9 @@ +1.084125496282453138e+00 +-4.642676300617178398e-01 +-6.658820752324799974e-01 +-1.228749652534838893e-01 +1.266842924569576145e-01 +3.397347243069742673e-01 +3.036887095295650041e-01 +2.213893524577207617e-01 +-1.886557316342868038e-02 \ No newline at end of file diff --git a/data/example_light_original/rotate_light_06.txt b/data/example_light_original/rotate_light_06.txt new file mode 100644 index 0000000..401426b --- /dev/null +++ b/data/example_light_original/rotate_light_06.txt @@ -0,0 +1,9 @@ +1.084125496282453138e+00 +-4.642676300617169516e-01 +-5.112381993903207800e-01 +4.439962822886048266e-01 +-1.866289387481862572e-01 +3.108669041197227867e-01 +2.021743042675238355e-01 +-3.148681770175290051e-01 +3.974379604123656762e-02 \ No newline at end of file diff --git a/obama.jpg b/obama.jpg new file mode 100644 index 0000000..f69fc88 Binary files /dev/null and b/obama.jpg differ diff --git a/requirment.txt b/requirment.txt new file mode 100644 index 0000000..a483f45 --- /dev/null +++ b/requirment.txt @@ -0,0 +1,36 @@ +cuda-bindings==13.2.0 +cuda-pathfinder==1.5.3 +cuda-toolkit==13.0.2 +filelock==3.29.0 +fsspec==2026.3.0 +jinja2==3.1.6 +markupsafe==3.0.3 +mpmath==1.3.0 +networkx==3.4.2 +numpy==2.2.6 +nvidia-cublas==13.1.0.3 +nvidia-cuda-cupti==13.0.85 +nvidia-cuda-nvrtc==13.0.88 +nvidia-cuda-runtime==13.0.96 +nvidia-cudnn-cu13==9.19.0.56 +nvidia-cufft==12.0.0.61 +nvidia-cufile==1.15.1.6 +nvidia-curand==10.4.0.35 +nvidia-cusolver==12.0.4.66 +nvidia-cusparse==12.6.3.3 +nvidia-cusparselt-cu13==0.8.0 +nvidia-nccl-cu13==2.28.9 +nvidia-nvjitlink==13.0.88 +nvidia-nvshmem-cu13==3.4.5 +nvidia-nvtx==13.0.85 +opencv-python==4.13.0.92 +pillow==12.2.0 +pip==22.0.2 +setuptools==59.6.0 +sympy==1.14.0 +torch==2.11.0 +torchaudio==2.11.0 +torchvision==0.26.0 +triton==3.6.0 +typing-extensions==4.15.0 +uv==0.11.7 diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/test_find_mapping.py b/test/test_find_mapping.py new file mode 100644 index 0000000..6b2b706 --- /dev/null +++ b/test/test_find_mapping.py @@ -0,0 +1,88 @@ +import cv2 +import numpy as np +from utils.find_mapping import create_lighting_filter, apply_lighting_filter, apply_shadow_enhancement, apply_darkening_from_gain +import unittest + + +class MyTestCase(unittest.TestCase): + def test_create_lighting_filter(self): + refrence_image: np.ndarray = cv2.imread("/home/abolfazl/Documents/DPR/obama.jpg") + target_image: np.ndarray = cv2.imread("candidiate_config/candidate1/result/rotate_light_06.jpg") + smooth_gain, b = create_lighting_filter(img_x=refrence_image, img_y=target_image) + cv2.imshow('Lighting Filter Map', smooth_gain) + cv2.waitKey(0) + cv2.destroyWindow("Lighting Filter Map") + print(50 * '=','Filter info', 50* '=') + print("reference image shape: ", refrence_image.shape) + print("target image shape: ", target_image.shape) + print("filter shape: ", smooth_gain.shape) + print("min value: ", smooth_gain.min()) + print("max value: ", smooth_gain.max()) + + def test_apply_smooth_gain(self): + refrence_image: np.ndarray = cv2.imread("/home/abolfazl/Documents/DPR/obama.jpg") + target_image: np.ndarray = cv2.imread("candidiate_config/candidate1/result/rotate_light_06.jpg") + smooth_gain, _ = create_lighting_filter(img_x=refrence_image, img_y=target_image) + cv2.imshow('Lighting Filter Map', smooth_gain) + cv2.waitKey(0) + cv2.destroyWindow("Lighting Filter Map") + result = apply_lighting_filter(refrence_image, smooth_gain) + cv2.imshow('Result', result) + cv2.waitKey(0) + cv2.destroyWindow("Result") + cv2.imwrite(f"apply-gain.jpg", result) + + def test_shadow_enhancement(self): + shadow_strength=0.9 + refrence_image: np.ndarray = cv2.imread("/home/abolfazl/Documents/DPR/obama.jpg") + target_image: np.ndarray = cv2.imread( + "candidiate_config/candidate1/result/rotate_light_06.jpg") + smooth_gain, lab_x = create_lighting_filter(img_x=refrence_image, img_y=target_image) + _, final_gain = apply_shadow_enhancement(lab_x, smooth_gain, shadow_strength=shadow_strength) + + cv2.imshow('Lighting Filter Map', final_gain) + cv2.waitKey(0) + cv2.destroyWindow("Lighting Filter Map") + print(50 * '=', 'Filter info', 50 * '=') + print("reference image shape: ", refrence_image.shape) + print("target image shape: ", target_image.shape) + print("filter shape: ", final_gain.shape) + print("min value: ", final_gain.min()) + print("max value: ", final_gain.max()) + + def test_apply_lighting_filter(self): + shadow_strength=0.9 + refrence_image: np.ndarray = cv2.imread("/home/abolfazl/Documents/DPR/obama.jpg") + target_image: np.ndarray = cv2.imread("candidiate_config/candidate1/result/rotate_light_06.jpg") + smooth_gain, lab_x = create_lighting_filter(img_x=refrence_image, img_y=target_image) + _, final_gain = apply_shadow_enhancement(lab_x, smooth_gain, shadow_strength=shadow_strength) + + + result = apply_lighting_filter(target_image, final_gain) + filter_vis = cv2.normalize(final_gain, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) + cv2.imshow('Lighting Filter Map', filter_vis) + cv2.waitKey(0) + + cv2.imwrite(f"/home/abolfazl/Documents/DPR/res_darker_{shadow_strength}.jpg", result) + cv2.imshow("result_img", result) + cv2.waitKey(0) + cv2.destroyAllWindows() + + + def test_darkening_from_gain(self): + refrence_image: np.ndarray = cv2.imread("/home/abolfazl/Documents/DPR/obama.jpg") + target_image: np.ndarray = cv2.imread("candidiate_config/candidate1/result/rotate_light_06.jpg") + smooth_gain, lab_x = create_lighting_filter(img_x=refrence_image, img_y=target_image) + cv2.imshow("filter", smooth_gain) + cv2.waitKey(0) + + final_gain = apply_darkening_from_gain(smooth_gain=smooth_gain, shadow_strength=1.5, curve_power=1.5) + result = apply_lighting_filter(target_img=refrence_image, gain_filter=final_gain) + cv2.imshow("dark filter", final_gain) + cv2.imshow("result", result) + cv2.waitKey(0) + cv2.destroyAllWindows() + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_light_condition.py b/test/test_light_condition.py new file mode 100644 index 0000000..ebbe966 --- /dev/null +++ b/test/test_light_condition.py @@ -0,0 +1,75 @@ +import os +import cv2 +import numpy as np + +from utils.testNetwork_demo_512 import test_network_demo_512 +from utils.testNetwork_demo_1024 import test_network_demo_1024 +import random +import unittest + + + +class MyTestCase(unittest.TestCase): + + def test_network_512_demo(self): + try: + test_network_demo_512(model_folder="trained_model/", + lightFolder="candidiate_config/candidate1", + saveFolder="candidiate_config/candidate1/result", + img="obama.jpg") + except Exception as error: + self.fail(f"test_network_demo_512 raised an exception: {error}") + + def test_network_1024_demo(self): + try: + test_network_demo_1024(model_folder="trained_model/", + lightFolder="candidiate_config/candidate3", + saveFolder="candidiate_config/candidate3/result1024", + img="obama.jpg") + except Exception as error: + self.fail(f"test_network_demo_1024 raised an exception: {error}") + + def test_create_different_lighting_condition(self, dir_name: None): + global __OUTPUT_PATH + config_file = "/home/abolfazl/Documents/DPR/data/example_light_1" + for file in os.listdir(config_file): + with open(os.path.join(config_file, file), mode='r') as txtFile: + normal_str = list(map(lambda inpt: format(float(inpt), '.20f') , txtFile.readlines())) + # ✅ تغییر عدد اول + if len(normal_str) > 0: + normal_str[0] = str(random.uniform(-1, 1)) + + # ✅ تغییر از عدد چهارم به بعد (index 3 به بعد) + for i in range(4, len(normal_str)): + normal_str[i] = str(random.uniform(0, 1)) + + if not os.path.exists(os.path.join(MyTestCase.OUTPUT_PATH, dir_name, "example_light")): + os.makedirs(os.path.join(MyTestCase.OUTPUT_PATH, dir_name, "example_light")) + with open(os.path.join(MyTestCase.OUTPUT_PATH, dir_name, "example_light", file), mode='w') as outFile: + outFile.write("\n".join(normal_str)) + + def test_apply_different_configs_on_imag(self, how_many_test: int = 10): + i = 1 + while i < how_many_test + 1: + self.test_create_different_lighting_condition(dir_name=f"test{i}") + try: + test_network_demo_512(model_folder="trained_model/", + lightFolder=os.path.join(MyTestCase.OUTPUT_PATH, f"test{i}", "example_light"), + saveFolder=os.path.join(MyTestCase.OUTPUT_PATH, f"test{i}"), + img="obama.jpg") + i += 1 + except Exception as error: + self.fail(f"test_network_demo_512 raised an exception: {error}") + + def test_make_darker_image(self, img_src: str="/home/abolfazl/Documents/DPR/data/obama.jpg", scale: float=0.3, output_path: str="/home/abolfazl/Documents/DPR"): + try: + raw_image = cv2.imread(img_src) + drk_image = (raw_image * scale).astype(np.uint8) + cv2.imwrite(os.path.join(output_path, img_src.split('/')[-1]), drk_image) + except FileExistsError as e: + print(f"error {e}") + except RuntimeError as e: + print(f"error {e}") + +if __name__ == '__main__': + unittest.main() diff --git a/testNetwork_demo_1024.py b/testNetwork_demo_1024.py deleted file mode 100644 index 7d24793..0000000 --- a/testNetwork_demo_1024.py +++ /dev/null @@ -1,96 +0,0 @@ -''' - this is a simple test file -''' -import sys -sys.path.append('model') -sys.path.append('utils') - -from utils_SH import * - -# other modules -import os -import numpy as np - -from torch.autograd import Variable -from torchvision.utils import make_grid -import torch -import time -import cv2 - -# ---------------- create normal for rendering half sphere ------ -img_size = 256 -x = np.linspace(-1, 1, img_size) -z = np.linspace(1, -1, img_size) -x, z = np.meshgrid(x, z) - -mag = np.sqrt(x**2 + z**2) -valid = mag <=1 -y = -np.sqrt(1 - (x*valid)**2 - (z*valid)**2) -x = x * valid -y = y * valid -z = z * valid -normal = np.concatenate((x[...,None], y[...,None], z[...,None]), axis=2) -normal = np.reshape(normal, (-1, 3)) -#----------------------------------------------------------------- - -modelFolder = 'trained_model/' - -# load model -from defineHourglass_1024_gray_skip_matchFeature import * -my_network_512 = HourglassNet(16) -my_network = HourglassNet_1024(my_network_512, 16) -my_network.load_state_dict(torch.load(os.path.join(modelFolder, 'trained_model_1024_03.t7'))) -my_network.cuda() -my_network.train(False) - - -lightFolder = 'data/example_light/' -saveFolder = 'result_1024' -if not os.path.exists(saveFolder): - os.makedirs(saveFolder) - - -img = cv2.imread('data/obama.jpg') -row, col, _ = img.shape -img = cv2.resize(img, (1024, 1024)) -Lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) - -inputL = Lab[:,:,0] -inputL = inputL.astype(np.float32)/255.0 -inputL = inputL.transpose((0,1)) -inputL = inputL[None,None,...] -inputL = Variable(torch.from_numpy(inputL).cuda()) - -for i in range(7): - sh = np.loadtxt(os.path.join(lightFolder, 'rotate_light_{:02d}.txt'.format(i))) - sh = sh[0:9] - sh = sh * 0.7 - - # rendering half-sphere - sh = np.squeeze(sh) - shading = get_shading(normal, sh) - value = np.percentile(shading, 95) - ind = shading > value - shading[ind] = value - shading = (shading - np.min(shading))/(np.max(shading) - np.min(shading)) - shading = (shading *255.0).astype(np.uint8) - shading = np.reshape(shading, (256, 256)) - shading = shading * valid - cv2.imwrite(os.path.join(saveFolder, \ - 'light_{:02d}.png'.format(i)), shading) - - #---------------------------------------------- - # rendering images using the network - #---------------------------------------------- - sh = np.reshape(sh, (1,9,1,1)).astype(np.float32) - sh = Variable(torch.from_numpy(sh).cuda()) - outputImg, _, outputSH, _ = my_network(inputL, sh, 0) - outputImg = outputImg[0].cpu().data.numpy() - outputImg = outputImg.transpose((1,2,0)) - outputImg = np.squeeze(outputImg) - outputImg = (outputImg*255.0).astype(np.uint8) - Lab[:,:,0] = outputImg - resultLab = cv2.cvtColor(Lab, cv2.COLOR_LAB2BGR) - resultLab = cv2.resize(resultLab, (col, row)) - cv2.imwrite(os.path.join(saveFolder, \ - 'obama_{:02d}.jpg'.format(i)), resultLab) diff --git a/testNetwork_demo_512.py b/testNetwork_demo_512.py deleted file mode 100644 index c6a9798..0000000 --- a/testNetwork_demo_512.py +++ /dev/null @@ -1,96 +0,0 @@ -''' - this is a simple test file -''' -import sys -sys.path.append('model') -sys.path.append('utils') - -from utils_SH import * - -# other modules -import os -import numpy as np - -from torch.autograd import Variable -from torchvision.utils import make_grid -import torch -import time -import cv2 - -# ---------------- create normal for rendering half sphere ------ -img_size = 256 -x = np.linspace(-1, 1, img_size) -z = np.linspace(1, -1, img_size) -x, z = np.meshgrid(x, z) - -mag = np.sqrt(x**2 + z**2) -valid = mag <=1 -y = -np.sqrt(1 - (x*valid)**2 - (z*valid)**2) -x = x * valid -y = y * valid -z = z * valid -normal = np.concatenate((x[...,None], y[...,None], z[...,None]), axis=2) -normal = np.reshape(normal, (-1, 3)) -#----------------------------------------------------------------- - -modelFolder = 'trained_model/' - -# load model -from defineHourglass_512_gray_skip import * -my_network = HourglassNet() -my_network.load_state_dict(torch.load(os.path.join(modelFolder, 'trained_model_03.t7'))) -my_network.cuda() -my_network.train(False) - -lightFolder = 'data/example_light/' - -saveFolder = 'result' -if not os.path.exists(saveFolder): - os.makedirs(saveFolder) - -img = cv2.imread('data/obama.jpg') -row, col, _ = img.shape -img = cv2.resize(img, (512, 512)) -Lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) - -inputL = Lab[:,:,0] -inputL = inputL.astype(np.float32)/255.0 -inputL = inputL.transpose((0,1)) -inputL = inputL[None,None,...] -inputL = Variable(torch.from_numpy(inputL).cuda()) - -for i in range(7): - sh = np.loadtxt(os.path.join(lightFolder, 'rotate_light_{:02d}.txt'.format(i))) - sh = sh[0:9] - sh = sh * 0.7 - - #-------------------------------------------------- - # rendering half-sphere - sh = np.squeeze(sh) - shading = get_shading(normal, sh) - value = np.percentile(shading, 95) - ind = shading > value - shading[ind] = value - shading = (shading - np.min(shading))/(np.max(shading) - np.min(shading)) - shading = (shading *255.0).astype(np.uint8) - shading = np.reshape(shading, (256, 256)) - shading = shading * valid - cv2.imwrite(os.path.join(saveFolder, \ - 'light_{:02d}.png'.format(i)), shading) - #-------------------------------------------------- - - #---------------------------------------------- - # rendering images using the network - sh = np.reshape(sh, (1,9,1,1)).astype(np.float32) - sh = Variable(torch.from_numpy(sh).cuda()) - outputImg, outputSH = my_network(inputL, sh, 0) - outputImg = outputImg[0].cpu().data.numpy() - outputImg = outputImg.transpose((1,2,0)) - outputImg = np.squeeze(outputImg) - outputImg = (outputImg*255.0).astype(np.uint8) - Lab[:,:,0] = outputImg - resultLab = cv2.cvtColor(Lab, cv2.COLOR_LAB2BGR) - resultLab = cv2.resize(resultLab, (col, row)) - cv2.imwrite(os.path.join(saveFolder, \ - 'obama_{:02d}.jpg'.format(i)), resultLab) - #---------------------------------------------- diff --git a/utils/find_mapping.py b/utils/find_mapping.py new file mode 100644 index 0000000..607428b --- /dev/null +++ b/utils/find_mapping.py @@ -0,0 +1,76 @@ +import cv2 +import numpy as np + + +def create_lighting_filter(img_x: np.ndarray, img_y: np.ndarray, epsilon: float=1e-5): + lab_x = cv2.cvtColor(img_x, cv2.COLOR_BGR2LAB).astype(np.float32) + lab_y = cv2.cvtColor(img_y, cv2.COLOR_BGR2LAB).astype(np.float32) + + lx = lab_x[:, :, 0] + ly = lab_y[:, :, 0] + + gain_map = ly / (lx + epsilon) + + gain_map = np.clip(gain_map, 0.1, 10.0) + radius = 100 + eps = 0.1 * (255 ** 2) + smooth_gain = cv2.ximgproc.guidedFilter(guide=lx.astype(np.uint8), + src=gain_map, + radius=radius, + eps=eps) + return smooth_gain, lab_x + # return gain_map, lab_x + +def apply_darkening_from_gain(smooth_gain: np.ndarray, + shadow_strength: float = 0.4, + curve_power: float = 1.5): + """ + Darkens the lighting filter itself, without using the image (L-channel). + Only modifies `smooth_gain` directly. + """ + + # Normalize gain to [0, 1] + g = smooth_gain.astype(np.float32) + g_norm = g / g.max() + + # Create a darkening curve entirely from the gain itself + # High gain → brighter areas → get reduced less + # Low gain → naturally darker → get reduced more + darkening_curve = (1.0 - shadow_strength * (1.0 - g_norm) ** curve_power) + + # Final filter + final_gain = g * darkening_curve + + return final_gain + +def apply_shadow_enhancement(lab_x: np.ndarray, smooth_gain: np.ndarray, shadow_strength: float = 0.4): + + lx = lab_x[:, :, 0].astype(np.float32) + + dark_weight = 1.0 - (lx / 255.0) + + dark_weight = dark_weight ** 2.5 + + darkening_filter = 1.0 - shadow_strength * dark_weight + + final_gain = smooth_gain * darkening_filter + + new_l = lx * final_gain + new_l = np.clip(new_l, 0, 255) + + result_lab = lab_x.copy() + result_lab[:, :, 0] = new_l + + result_bgr = cv2.cvtColor(result_lab.astype(np.uint8), cv2.COLOR_LAB2BGR) + return result_bgr, final_gain + +def apply_lighting_filter(target_img: np.ndarray, gain_filter: np.ndarray): + + lab = cv2.cvtColor(target_img, cv2.COLOR_BGR2LAB).astype(np.float32) + + lab[:, :, 0] = lab[:, :, 0] * gain_filter + + lab[:, :, 0] = np.clip(lab[:, :, 0], 0, 255) + + result = cv2.cvtColor(lab.astype(np.uint8), cv2.COLOR_LAB2BGR) + return result diff --git a/utils/testNetwork_demo_1024.py b/utils/testNetwork_demo_1024.py new file mode 100644 index 0000000..6effba4 --- /dev/null +++ b/utils/testNetwork_demo_1024.py @@ -0,0 +1,108 @@ +import sys +sys.path.append('model') +sys.path.append('utils') + +from utils_SH import * + +# other modules +import os +import numpy as np +from defineHourglass_1024_gray_skip_matchFeature import * +from torch.autograd import Variable +from torchvision.utils import make_grid +import torch +import time +import cv2 + +__IMG_SIZE = 256 + +def test_network_demo_1024(**kwargs) -> None: + # --------------------- configs --------------------- + modelFolder = kwargs.get("modelFolder", 'trained_model/') + lightFolder = kwargs.get("lightFolder", 'data/example_light/') + saveFolder = kwargs.get("saveFolder", 'result_1024') + img = kwargs.get("img", 'data/obama.jpg') + net = None + + # ---------------- create normal for rendering half sphere ------ + x = np.linspace(-1, 1, __IMG_SIZE) + z = np.linspace(1, -1, __IMG_SIZE) + x, z = np.meshgrid(x, z) + + mag = np.sqrt(x**2 + z**2) + valid = mag <=1 + y = -np.sqrt(1 - (x*valid)**2 - (z*valid)**2) + x = x * valid + y = y * valid + z = z * valid + normal = np.concatenate((x[...,None], y[...,None], z[...,None]), axis=2) + normal = np.reshape(normal, (-1, 3)) + #----------------------------------------------------------------- + + + + # load model + try: + net = HourglassNet(16) + net = HourglassNet_1024(net, 16) + net.load_state_dict(torch.load(os.path.join(modelFolder, 'trained_model_1024_03.t7'))) + net.cuda() + net.train(False) + except FileExistsError as e: + print(f"File error '{e}'") + + except RuntimeError as e: + print(f"RunTimeError as '{e}'") + + except Exception as e: + print(f"Error '{e}'") + + if not os.path.exists(saveFolder): + os.makedirs(saveFolder) + + + img = cv2.imread(img) + row, col, _ = img.shape + img = cv2.resize(img, (1024, 1024)) + Lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) + + inputL = Lab[:,:,0] + inputL = inputL.astype(np.float32)/255.0 + inputL = inputL.transpose((0,1)) + inputL = inputL[None,None,...] + inputL = Variable(torch.from_numpy(inputL).cuda()) + + for file in os.listdir(lightFolder): + if os.path.isdir(os.path.join(lightFolder, file)): + continue + sh = np.loadtxt(os.path.join(lightFolder, file)) + sh = sh[0:9] + sh = sh * 0.7 + + # rendering half-sphere + sh = np.squeeze(sh) + shading = get_shading(normal, sh) + value = np.percentile(shading, 95) + ind = shading > value + shading[ind] = value + shading = (shading - np.min(shading))/(np.max(shading) - np.min(shading)) + shading = (shading *255.0).astype(np.uint8) + shading = np.reshape(shading, (256, 256)) + shading = shading * valid + cv2.imwrite(os.path.join(saveFolder, file.replace(".txt", '.jpg')), shading) + + + #---------------------------------------------- + # rendering images using the network + #---------------------------------------------- + sh = np.reshape(sh, (1,9,1,1)).astype(np.float32) + sh = Variable(torch.from_numpy(sh).cuda()) + outputImg, _, outputSH, _ = net(inputL, sh, 0) + outputImg = outputImg[0].cpu().data.numpy() + outputImg = outputImg.transpose((1,2,0)) + outputImg = np.squeeze(outputImg) + outputImg = (outputImg*255.0).astype(np.uint8) + Lab[:,:,0] = outputImg + resultLab = cv2.cvtColor(Lab, cv2.COLOR_LAB2BGR) + resultLab = cv2.resize(resultLab, (col, row)) + cv2.imwrite(os.path.join(saveFolder, file.replace(".txt", '.jpg')), resultLab) diff --git a/utils/testNetwork_demo_512.py b/utils/testNetwork_demo_512.py new file mode 100644 index 0000000..0c53391 --- /dev/null +++ b/utils/testNetwork_demo_512.py @@ -0,0 +1,107 @@ +import sys +sys.path.append('model') +sys.path.append('utils') + +from utils_SH import * + +# other modules +import os +import numpy as np + +from torch.autograd import Variable +from torchvision.utils import make_grid +import torch +import time +import cv2 +from defineHourglass_512_gray_skip import * + +__IMG_SIZE = 256 + +def test_network_demo_512(**kwargs) -> None: + # --------------------- set configs --------------------- + modelFolder = kwargs.get("model_folder", "trained_model/") + lightFolder = kwargs.get("lightFolder", "data/example_light_1/") + saveFolder = kwargs.get("saveFolder", "result1") + img = kwargs.get("img", "data/obama.jpg") + + # ---------------- create normal for rendering half sphere ------ + x = np.linspace(-1, 1, __IMG_SIZE) + z = np.linspace(1, -1, __IMG_SIZE) + x, z = np.meshgrid(x, z) + net = None + mag = np.sqrt(x**2 + z**2) + valid = mag <=1 + y = -np.sqrt(1 - (x*valid)**2 - (z*valid)**2) + x = x * valid + y = y * valid + z = z * valid + normal = np.concatenate((x[...,None], y[...,None], z[...,None]), axis=2) + normal = np.reshape(normal, (-1, 3)) + #----------------------------------------------------------------- + # load model + try: + net = HourglassNet() + net.load_state_dict(torch.load(os.path.join(modelFolder, 'trained_model_03.t7'))) + net.cuda() + net.train(False) + except FileExistsError as e: + print(f"File error as '{e}'") + except RuntimeError as e: + print(f"RunTimeError as '{e}'") + except Exception as e: + print(f"Error as '{e}'") + + if not os.path.exists(saveFolder): + os.makedirs(saveFolder) + + img = cv2.imread(img) + row, col, _ = img.shape + img = cv2.resize(img, (512, 512)) + Lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) + + inputL = Lab[:,:,0] + inputL = inputL.astype(np.float32)/255.0 + inputL = inputL.transpose((0,1)) + inputL = inputL[None,None,...] + inputL = Variable(torch.from_numpy(inputL).cuda()) + + for file in os.listdir(lightFolder): + if os.path.isdir(os.path.join(lightFolder, file)): + continue + sh = np.loadtxt(os.path.join(lightFolder, file)) + sh = sh[0:9] + sh = sh * 0.7 + + #-------------------------------------------------- + # rendering half-sphere + sh = np.squeeze(sh) + shading = get_shading(normal, sh) + value = np.percentile(shading, 95) + ind = shading > value + shading[ind] = value + shading = (shading - np.min(shading))/(np.max(shading) - np.min(shading)) + shading = (shading *255.0).astype(np.uint8) + shading = np.reshape(shading, (256, 256)) + shading = shading * valid + # cv2.imwrite(os.path.join(saveFolder, \ + # 'light_{:02d}.png'.format(i)), shading) + + cv2.imwrite(os.path.join(saveFolder, file.replace(".txt", '.jpg')), shading) + + #-------------------------------------------------- + + #---------------------------------------------- + # rendering images using the network + sh = np.reshape(sh, (1,9,1,1)).astype(np.float32) + sh = Variable(torch.from_numpy(sh).cuda()) + outputImg, outputSH = net(inputL, sh, 0) + outputImg = outputImg[0].cpu().data.numpy() + outputImg = outputImg.transpose((1,2,0)) + outputImg = np.squeeze(outputImg) + outputImg = (outputImg*255.0).astype(np.uint8) + Lab[:,:,0] = outputImg + resultLab = cv2.cvtColor(Lab, cv2.COLOR_LAB2BGR) + resultLab = cv2.resize(resultLab, (col, row)) + + cv2.imwrite(os.path.join(saveFolder, file.replace(".txt", '.jpg')), resultLab) + #----------------------------------------------