Reputation: 5540
I want to replicate the GIMP Filter > Edge Decect > Difference of Gaussians in C++ using opencv.
I found this simple code for DOG implementation bu I want the same result of GIMP with the two params Raidus1 and Radius2.
Mat g1, g2, result;
Mat img = imread("test.png", CV_LOAD_IMAGE_COLOR);
GaussianBlur(img, g1, Size(1,1), 0);
GaussianBlur(img, g2, Size(3,3), 0);
result = g1 - g2;
How can add the 2 radius params to the implementation?
If can help this is the link to the C implementation of the filter
https://gitlab.gnome.org/GNOME/gimp/blob/master/plug-ins/common/edge-dog.c
Upvotes: 1
Views: 1493
Reputation: 880
It looks like missing a line. From lines 729-730 of edge-dog.c:
radius = fabs (radius) + 1.0;
std_dev = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0)));
Gimp then computes the Gaussian as list of integers in make_curve(std_dev, ...). Note
Upvotes: 0
Reputation: 207445
I don't have the answer, but have run out of hair - see comment. I have been working on this and have some code that doesn't work, but somebody cleverer than me who doesn't feel like writing code, may be able to see what is wrong, so I thought I would share what I have. I am not interested in any points, so anyone is welcome to take and adapt this and show a working answer. Fine by me if we find a solution. I did it in Python but I am sure we can easily adapt any Python to C++ if we get something that works.
#!/usr/bin/env python3
import numpy as np
import math
import cv2
def radius2stdev(radius):
"""
Return std deviation corresponding to a given radius.
I got this from: https://gitlab.gnome.org/GNOME/gimp/blob/master/plug-ins/common/edge-dog.c
"""
stdev = math.sqrt (-(radius * radius) / (2 * math.log (1.0 / 255.0)));
return stdev
# Load image, make float and scale to range 0..1
im = cv2.imread("image.jpg",cv2.IMREAD_COLOR).astype(np.float)
im = im/255.0
stdev1 = radius2stdev(22.0)
stdev2 = radius2stdev(5.0)
print('Stdev1: {}'.format(stdev1))
print('Stdev2: {}'.format(stdev2))
# Generate the two Gaussians and their difference
# I believe OpenCV calculates the size of the kernel to match the std dev if you pass no kernel size
# See https://docs.opencv.org/3.4.1/d4/d86/group__imgproc__filter.html#gaabe8c836e97159a9193fb0b11ac52cf1
g1 = cv2.GaussianBlur(im,(0,0),stdev1,stdev1)
g2 = cv2.GaussianBlur(im,(0,0),stdev2,stdev2)
result = g1 -g2
# Multiply back up by 255 and save as PNG
result = (result * 255).astype(np.uint8)
cv2.imwrite("result.png", result)
# Normalize and save normalised too
resultn = cv2.normalize(result,None,alpha=0,beta=255,norm_type=cv2.NORM_MINMAX)
cv2.imwrite("result-n.png", resultn)
The standard deviations are printed out like this:
Stdev1: 6.608505869104614
Stdev2: 1.5019331520692305
I believe the 22,000 and 5,000 shown for your radii are just a result of your internationalisation and these correspond to 22.0 and 5.0 in US/UK format.
I also had an attempt with ImageMagick on the command-line and got something vaguely similar though I am not sure what that proves:
magick image.jpg -morphology Convolve DoG:0,20,5 -evaluate multiply 6 result.jpg
Upvotes: 1