Skip to content

Commit 5404779

Browse files
author
Philip Meier
authored
add results and code
2 parents 0715134 + 4ab2716 commit 5404779

File tree

102 files changed

+3657
-16
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+3657
-16
lines changed

README.md

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,42 @@
1-
This repository will contain the source code to reproduce the results of the paper
1+
This repository contains the source code to reproduce the results of the paper
22

33
"Content representation for Neural Style Transfer Algorithms based on Structural Similarity"
44

5-
written by [Philip Meier](https://www.th-owl.de/init/en/das-init/team/c/meier-5.html) and [Volker Lohweg](https://www.th-owl.de/init/en/das-init/team/c/lohweg-1.html). It will be available after the paper is presented at the [29. Workshop "Computational Intelligence"](http://www.rst.e-technik.tu-dortmund.de/cms/de/Veranstaltungen/GMA-Fachausschuss/index.html) on the 28th and 29th of November 2019 in Dortmund, Germany.
5+
written by [Philip Meier](https://www.th-owl.de/init/en/das-init/team/c/meier-5.html) and [Volker Lohweg](https://www.th-owl.de/init/en/das-init/team/c/lohweg-1.html). It was presented at the [29. Workshop "Computational Intelligence"](http://www.rst.e-technik.tu-dortmund.de/cms/de/Veranstaltungen/GMA-Fachausschuss/index.html) on the 28th and 29th of November 2019 in Dortmund, Germany.
66

7-
# Accepted Abstract
7+
If you use this work within a scientific publication, please cite it as
88

9-
Within the field of non-photorealistic rendering (NPR) the term style transfer describes a process, which applies an abstract style to an image without changing the underlying content. The emergence of neural style transfer (NST) techniques, which were pioneered by Gatys, Ecker, and Bethge in 2016 [GEB16], marks a paradigm shift within this field. While traditional NPR methods operate within the pixel space [EF01], NST algorithms utilise the feature space of convolutional neural networks (CNNs) trained on object classification tasks. This enables a general style transfer from a single example image of the intended style. The quality of the resulting image is sometimes high enough to even fool art critics [San+18].
9+
```
10+
@InProceedings{ML2019,
11+
author = {Meier, Philip and Lohweg, Volker},
12+
title = {Content Representation for Neural Style Transfer Algorithms based on Structural Similarity},
13+
booktitle = {Proceedings of the 28\textsuperscript{th} Workshop Computational Intelligence},
14+
year = {2019},
15+
url = {https://github.com/pmeier/GMA_CI_2019_ssim_content_loss},
16+
}
17+
```
1018

11-
NST techniques treat the style of an image as texture. Thus, its representation involves various forms of global [GEB16; RWB17] and local statistics [LW16]. Within the original formulation, the content of an image is directly represented by the encodings from a deep layer of the CNN [GEB16]. These encodings are subsequently compared with their mean squared error (MSE). To the best knowledge of the authors currently no publication deals with alternative representations of the content. This contribution will change this by introducing a content representation based on the structural similarity (SSIM) index. The SSIM index was introduced by Wang et al. as a measure for image quality [Wan+04]. It was developed in order to compare two images with an objective measure that is aligned with the human perception opposed to conventional methods such as the MSE or the peak signal-to-noise-ratio. The SSIM index is incorporated as content representation into NST algorithms by utilising it as comparison between encodings of a CNN.
19+
The paper is part the conference proceedings, which are [openly accessible](https://dx.doi.org/10.5445/KSP/1000098736).
1220

13-
The proposed approach will be evaluated in two stages. An objective comparison between different NST algorithms is not possible within the current state of the art, since the quality of the stylisation is highly subjective. Thus, this contribution will focus on content reconstruction in a first step. Images reconstructed by different algorithms can be objectively compared to the original, for example by the SSIM index or the number of matching descriptors of the speeded up robust features (SURF) algorithm [BTv06]. In the second step the proposed content representation is utilised within an NST algorithm and qualitatively compared to the original formulation.
21+
# Installation
1422

15-
## References
23+
Clone this repository
1624

17-
Symbol | Reference
18-
--- | ---
19-
BTv06 | Bay, Herbert; Tuytelaars, Tinne; van Gool, Luc: ‘SURF: Speeded Up Robust Features’. In: Proceedings of the 9th European Conference on Computer Vision (ECCV). 2006.
20-
EF01 | Efros, Alexei A.; Freeman, William T.: ‘Image Quilting for Texture Synthesis and Transfer’. In: Proceedings of the 28th Annual Conference on Computer Graphics and Interactive Techniques (SIGGRAPH). 2001. DOI: [10.1145/383259.383296](https://dl.acm.org/citation.cfm?doid=383259.383296).
21-
GEB16 | Gatys, Leon A.; Ecker, Alexander S.; Bethge, Matthias: ‘Image Style Transfer Using Convolutional Neural Networks’. In: Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR). 2016. DOI: [10.1109/CVPR.2016.265](https://ieeexplore.ieee.org/document/7780634).
22-
LW16 | Li, Chuan; Wand, Michael: ‘Combining Markov Random Fields and Convolutional Neural Networks for Image Synthesis’. In: Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR). 2016. DOI: [10.1109/CVPR.2016.272](https://ieeexplore.ieee.org/document/7780641).
23-
RWB17 | Risser, Eric; Wilmot, Pierre; Barnes, Connelly: [‘Stable and Controllable Neural Texture Synthesis and Style Transfer Using Histogram Losses’](https://arxiv.org/abs/1701.08893). In: Computing Research Repository (CoRR) 1701 (2017).
24-
San+18 | Sanakoyeu, Artsiom et al.: [‘A Style-Aware Content Loss for Real-time HD Style Transfer’](https://arxiv.org/abs/1807.10201). In: Computing Research Repository (CoRR) 1807 (2018).
25-
Wan+04 | Wang, Zhou et al.: ‘Image quality assessment: from error visibility to structural similarity’. In: IEEE Transactions on Image Processing 13.4 (2004). DOI: [10.1109/TIP.2003.819861](https://ieeexplore.ieee.org/document/1284395).
25+
`git clone https://github.com/pmeier/GMA_CI_2019_ssim_content_loss`
26+
27+
and install the required packages
28+
29+
```
30+
cd GMA_CI_2019_ssim_content_loss
31+
pip install -r requirements
32+
```
33+
34+
If you experience problems while installing `torch` or `torchvision`, please follow the [official installation instructions](https://pytorch.org/get-started/locally/) for your setup.
35+
36+
# Replication
37+
38+
All results are contained in the `results` folder. If you want to replicate the results yourself you need to
39+
40+
1. download the source images by running `images.py`,
41+
2. perform the experiments by running `experiments.py`, and
42+
3. finally run `process.py` to process the raw experiment results.

experiments.py

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
from os import path
2+
import itertools
3+
import numpy as np
4+
import pandas as pd
5+
import torch
6+
from torchimagefilter import GaussFilter, BoxFilter
7+
from torchssim import SimplifiedMSSIM
8+
from pystiche.image import read_image, write_image, extract_image_size
9+
from pystiche.image.transforms import Resize, RGBToGrayscale
10+
from utils import make_reproducible, intgeomspace, df_to_csv
11+
from images import (
12+
get_npr_general_files,
13+
get_npr_general_proxy_file,
14+
get_style_image_files,
15+
)
16+
from nst import MeierLohweg2019NCRPyramid, MeierLohweg2019NSTPyramid
17+
from recording import record_nst
18+
19+
20+
def get_eval_transform(image):
21+
eval_transform = Resize(extract_image_size(image)) + RGBToGrayscale()
22+
return eval_transform.to(image.device)
23+
24+
25+
def get_input_image(target_image, random=True):
26+
if random:
27+
return torch.rand_like(target_image)
28+
else:
29+
return target_image.clone()
30+
31+
32+
def perform_ncr(
33+
target_image, seed=0, level_steps=None, quiet=True, print_steps=None, **kwargs
34+
):
35+
device = target_image.device
36+
make_reproducible(seed)
37+
input_image = get_input_image(target_image, random=True)
38+
39+
ncr_pyramid = MeierLohweg2019NCRPyramid(**kwargs)
40+
ncr_pyramid = ncr_pyramid.to(device)
41+
ncr_pyramid.build_levels(level_steps)
42+
43+
ncr_pyramid.ncr.content_operator.set_target(target_image)
44+
45+
output_images = ncr_pyramid(input_image, quiet=quiet, print_steps=print_steps)
46+
47+
return output_images[-1]
48+
49+
50+
def perform_nst(content_image, style_image, quiet=True, print_steps=None, **kwargs):
51+
device = content_image.device
52+
make_reproducible()
53+
input_image = get_input_image(content_image, random=False)
54+
55+
nst_pyramid = MeierLohweg2019NSTPyramid(**kwargs)
56+
nst_pyramid = nst_pyramid.to(device)
57+
nst_pyramid.build_levels()
58+
59+
nst_pyramid.nst.content_operator.set_target(content_image)
60+
nst_pyramid.nst.style_operator.set_target(style_image)
61+
62+
output_images = nst_pyramid(input_image, quiet=quiet, print_steps=print_steps)
63+
64+
return output_images[-1]
65+
66+
67+
def benchmark_ncr(images_root, results_root, device):
68+
target_files = get_npr_general_files()
69+
ssim_component_weight_ratios = (0.0, 3.0, 9.0, np.inf)
70+
num_seeds = 5
71+
72+
loss_variations = [
73+
(True, ssim_component_weight_ratio)
74+
for ssim_component_weight_ratio in ssim_component_weight_ratios
75+
]
76+
loss_variations = [(False, None)] + loss_variations
77+
seeds = np.arange(num_seeds)
78+
79+
calculate_ssim_score = SimplifiedMSSIM().to(device)
80+
data = []
81+
for target_file in target_files:
82+
target_name = path.splitext(path.basename(target_file))[0]
83+
target_image = read_image(path.join(images_root, target_file)).to(device)
84+
85+
eval_transform = get_eval_transform(target_image)
86+
target_image_eval = eval_transform(target_image)
87+
88+
for loss_variation, seed in itertools.product(loss_variations, seeds):
89+
ssim_loss, ssim_component_weight_ratio = loss_variation
90+
91+
output_image = perform_ncr(
92+
target_image,
93+
seed=seed,
94+
ssim_loss=ssim_loss,
95+
ssim_component_weight_ratio=ssim_component_weight_ratio,
96+
)
97+
output_image_eval = eval_transform(output_image)
98+
99+
mssim = calculate_ssim_score(output_image_eval, target_image_eval)
100+
ssim_score = mssim.cpu().item()
101+
102+
data.append(
103+
(target_name, ssim_loss, ssim_component_weight_ratio, seed, ssim_score)
104+
)
105+
106+
columns = ("name", "ssim_loss", "ssim_component_weight_ratio", "seed", "ssim_score")
107+
df = pd.DataFrame.from_records(data, columns=columns)
108+
file = path.join(results_root, "ncr_benchmark", "raw.csv")
109+
df_to_csv(df, file)
110+
111+
112+
def evaluate_steady_state(images_root, results_root, device):
113+
target_file = path.join(images_root, get_npr_general_proxy_file())
114+
num_steps = 200_000
115+
116+
target_image = read_image(target_file).to(device)
117+
level_steps = (0, num_steps)
118+
print_steps = intgeomspace(1, num_steps, num=1000)
119+
120+
for ssim_loss in (False, True):
121+
with record_nst(quiet=True) as recorder:
122+
perform_ncr(
123+
target_image,
124+
level_steps=level_steps,
125+
quiet=False,
126+
print_steps=print_steps,
127+
ssim_loss=ssim_loss,
128+
diagnose_ssim_score=True,
129+
)
130+
131+
df = recorder.extract()
132+
133+
loss_type = "SSIM" if ssim_loss else "SE"
134+
df = df.rename(
135+
columns={f"Content loss ({loss_type})": "loss", "SSIM score": "ssim_score"}
136+
)
137+
df = df[["ssim_score", "loss"]]
138+
df = df.dropna(axis="index", how="all")
139+
140+
file = f"{loss_type.lower()}.csv"
141+
file = path.join(results_root, "steady_state", "raw", file)
142+
df_to_csv(df, file, index=False)
143+
144+
145+
def evaluate_ssim_window(images_root, results_root, device):
146+
target_file = path.join(images_root, get_npr_general_proxy_file())
147+
window_types = ("gauss", "box")
148+
output_shapes = ("same", "valid")
149+
radii = range(1, 10)
150+
num_seeds = 5
151+
152+
target_image = read_image(target_file).to(device)
153+
154+
eval_transform = get_eval_transform(target_image)
155+
target_image_eval = eval_transform(target_image)
156+
157+
def get_image_filter(window_type, output_shape, radius):
158+
kwargs = {"output_shape": output_shape, "padding_mode": "replicate"}
159+
if window_type == "gauss":
160+
return GaussFilter(radius=radius, std=radius / 3.0, **kwargs)
161+
else: # filter_type == "box"
162+
return BoxFilter(radius=radius, **kwargs)
163+
164+
seeds = range(num_seeds)
165+
166+
calculate_mssim = SimplifiedMSSIM().to(device)
167+
data = []
168+
169+
for image_filter_params in itertools.product(window_types, output_shapes, radii):
170+
image_filter = get_image_filter(*image_filter_params)
171+
172+
for seed in seeds:
173+
174+
kwargs = {"seed": seed, "image_filter": image_filter}
175+
output_image = perform_ncr(target_image, **kwargs)
176+
output_image_eval = eval_transform(output_image)
177+
178+
mssim = calculate_mssim(output_image_eval, target_image_eval)
179+
ssim_score = mssim.cpu().item()
180+
data.append((*image_filter_params, seed, ssim_score))
181+
182+
columns = ("window_type", "output_shape", "radius", "seed", "ssim_score")
183+
df = pd.DataFrame.from_records(data, columns=columns)
184+
file = path.join(results_root, "ssim_window", "raw.csv")
185+
df_to_csv(df, file)
186+
187+
188+
def benchmark_nst(images_root, results_root, device):
189+
def process_image(file):
190+
name = path.splitext(path.basename(file))[0]
191+
image = read_image(path.join(images_root, file)).to(device)
192+
return name, image
193+
194+
content_files = get_npr_general_files()
195+
style_files = get_style_image_files()
196+
197+
for content_file in content_files:
198+
content_name, content_image = process_image(content_file)
199+
for style_file in style_files:
200+
style_name, style_image = process_image(style_file)
201+
202+
for ssim_loss in (False, True):
203+
output_image = perform_nst(
204+
content_image, style_image, ssim_loss=ssim_loss, quiet=False
205+
)
206+
207+
output_file = "__".join(
208+
(content_name, style_name, "ssim" if ssim_loss else "se")
209+
)
210+
output_file = path.join(
211+
results_root, "nst_benchmark", f"{output_file}.jpg"
212+
)
213+
write_image(output_image, output_file)
214+
215+
216+
if __name__ == "__main__":
217+
root = path.dirname(__file__)
218+
images_root = path.join(root, "images")
219+
results_root = path.join(root, "results")
220+
221+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
222+
223+
benchmark_ncr(images_root, results_root, device)
224+
evaluate_steady_state(images_root, results_root, device)
225+
evaluate_ssim_window(images_root, results_root, device)
226+
benchmark_nst(images_root, results_root, device)

0 commit comments

Comments
 (0)