Created
May 30, 2024 12:07
-
-
Save andersource/8e2ffa2382fca01f176420f54332ba22 to your computer and use it in GitHub Desktop.
Spraying Digital Graffiti
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
from skimage.io import imread, imsave | |
from skimage.filters.edges import sobel | |
from skimage.color import rgb2gray | |
from skimage.transform import rescale | |
from scipy import ndimage | |
from skimage import measure | |
from skimage import graph | |
def main(): | |
DOWNSCALE_FACTOR = .3 | |
im1 = rescale(imread("/path/to/wall.jpg"), DOWNSCALE_FACTOR, channel_axis=-1) | |
im2 = rescale(imread("/path/to/painted_wall.jpg"), DOWNSCALE_FACTOR, channel_axis=-1) | |
mask = rescale(imread("/path/to/binary_mask.png")[..., 0] < 100, DOWNSCALE_FACTOR, order=0) | |
edgemap = sobel(rgb2gray(im1)) | |
contours = measure.find_contours(mask) | |
contours = [ | |
fix_contour(contour.round().astype(int), edgemap) | |
for contour in contours | |
] | |
final_mask = np.zeros(edgemap.shape, int) | |
for contour in contours: | |
final_mask = np.maximum(fill_contour(edgemap.shape, contour), final_mask) | |
final_mask = final_mask.reshape((*final_mask.shape, 1)) | |
res = final_mask * im2 + (1 - final_mask) * im1 | |
imsave("/path/to/result.png", res) | |
def fix_contour(contour, edgemap, weight_coef=1): | |
edge_weight = 50 | |
if np.std(contour, axis=0).mean() < 16: | |
edge_weight = 42 | |
temp = np.zeros(edgemap.shape, bool) | |
temp[contour[:, 0], contour[:, 1]] = 1 | |
dist = ndimage.distance_transform_edt(~temp) | |
sample_indices = sample_contour(contour, edgemap) | |
cost = dist + edgemap * edge_weight * weight_coef | |
total_path = [] | |
for i in range(sample_indices.shape[0] - 1): | |
p, _ = graph.route_through_array(cost, contour[sample_indices[i]], contour[sample_indices[i + 1]], geometric=False) | |
p = np.array(p) | |
total_path.append(p) | |
p, _ = graph.route_through_array(cost, contour[sample_indices[-1]], contour[sample_indices[0]], geometric=False) | |
p = np.array(p) | |
total_path.append(p) | |
p = np.concatenate(total_path) | |
return p[:, 0], p[:, 1] | |
def fill_contour(shape, contour): | |
res = np.zeros(shape, dtype=bool) | |
res[contour] = 1 | |
res = ndimage.binary_fill_holes(res) | |
return res | |
def sample_contour(contour, edgemap, N=100): | |
max_deviation = 7 if np.std(contour, axis=0).mean() < 16 else 20 | |
indices = (np.arange(N) * contour.shape[0] / N).round().astype(int) | |
for i in range(indices.shape[0]): | |
idx_alternatives = np.clip(indices[i] + np.arange(-max_deviation, max_deviation + 1), 0, contour.shape[0] - 1) | |
indices[i] = idx_alternatives[edgemap[contour[idx_alternatives][:, 0], contour[idx_alternatives][:, 1]].argmin()] | |
return indices | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
numpy | |
scipy | |
scikit-image |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment