Replace color in image measured by Euclidean distance












10












$begingroup$


This script replaces the red hair in image to black color (replace one color to another)





Three major parts in this script




  • Not just replace color red to black, I hope the output image looks natural, so I will replace the color close to red to black. This "close" is measured by Euclidean distance.


  • And not just replace by black color, user can modify the red color's r, g, b value separately, like add more green.


  • Choose the area to be changed, rather than change the whole picture





Suggestions I am looking for:




  • I did some NumPy practice before, so any suggestions about NumPy are welcome.


  • I think the code to replace target area is not so elegant, I am not quite sure about this part:



    (c1, r1), (c2, r2) = area
    for i in range(r1, r2+1):
    l, r = i*h+c1, i*h+c2+1
    data[l:r,:k][D[l:r]] = modification(data[l:r,:k][D[l:r]])





Full code:



import numpy as np
from PIL import Image
from scipy.spatial.distance import cdist

def replace_corlor(image, original_corlor, modification, area=None, distance=1000, output="new_test.jpg"):
print("[*] START Replace Color")
img = Image.open(image)
data = np.asarray(img, dtype="int32")
w,h,k = data.shape
data = np.reshape(data, (w*h,k))
distMatrix = cdist(data, np.array([original_corlor]))
D = distMatrix<=distance
D = np.reshape(D,w*h)
if area is None:
data[:,:k][D] = modification(data[:,:k][D])
else:
(c1, r1), (c2, r2) = area
for i in range(r1, r2+1):
l, r = i*h+c1, i*h+c2+1
data[l:r,:k][D[l:r]] = modification(data[l:r,:k][D[l:r]])
data = np.reshape(data, (w,h,k))
img = Image.fromarray(np.asarray(np.clip(data, 0, 255), dtype="uint8"), "RGB")
img.save(output)
print("[*] DONE Replace Color")

if __name__ == "__main__":
def modification(color):
return color * [2,0,0]
# return [255,0,0]
replace_corlor("test.jpg",(36,35,30),modification, ((0,0),(400,100)))









share|improve this question











$endgroup$








  • 1




    $begingroup$
    I have no comments on your code, your Python is better than mine. :) But for color modification you could use the distance to the original_color value. The larger this distance (and the closer the distance is to the distance threshold), the less you modify the color. This way, you will get a smoother transition at the edges of the red region.
    $endgroup$
    – Cris Luengo
    Nov 14 '18 at 5:42










  • $begingroup$
    @CrisLuengo Ah good advice!, thank you ^^
    $endgroup$
    – Aries_is_there
    Nov 14 '18 at 5:56










  • $begingroup$
    Couple of points, firstly, it appears that the modification function only works if it operates on vectors, rather than a single pixel, as you're passing that function the whole image at once. In some ways, it is doing most of the work. Secondly, There's a typo in the variable name original_corlor, nothing major, just confused me for a second. I find the contents of the else clause very confusing, partly because of very short variable names.
    $endgroup$
    – gbartonowen
    Jan 30 at 18:18










  • $begingroup$
    @gbartonowen sorry I don't get what you mean "it operates on vectors, rather than a single pixel", there is a area in parameters, if you wanna just change one pixel, for example the first pixel, just set area=((0,0),(1,1)), and about the typo, you are totally right
    $endgroup$
    – Aries_is_there
    Feb 17 at 18:34










  • $begingroup$
    @Aries_is_there The modification function takes a 3D array of pixels, rather than a single pixel, which means you must formulate the function as numpy compatible operators. In this case it works fine but it looks like a happens to work rather than is meant to work like this
    $endgroup$
    – gbartonowen
    Feb 19 at 10:06
















10












$begingroup$


This script replaces the red hair in image to black color (replace one color to another)





Three major parts in this script




  • Not just replace color red to black, I hope the output image looks natural, so I will replace the color close to red to black. This "close" is measured by Euclidean distance.


  • And not just replace by black color, user can modify the red color's r, g, b value separately, like add more green.


  • Choose the area to be changed, rather than change the whole picture





Suggestions I am looking for:




  • I did some NumPy practice before, so any suggestions about NumPy are welcome.


  • I think the code to replace target area is not so elegant, I am not quite sure about this part:



    (c1, r1), (c2, r2) = area
    for i in range(r1, r2+1):
    l, r = i*h+c1, i*h+c2+1
    data[l:r,:k][D[l:r]] = modification(data[l:r,:k][D[l:r]])





Full code:



import numpy as np
from PIL import Image
from scipy.spatial.distance import cdist

def replace_corlor(image, original_corlor, modification, area=None, distance=1000, output="new_test.jpg"):
print("[*] START Replace Color")
img = Image.open(image)
data = np.asarray(img, dtype="int32")
w,h,k = data.shape
data = np.reshape(data, (w*h,k))
distMatrix = cdist(data, np.array([original_corlor]))
D = distMatrix<=distance
D = np.reshape(D,w*h)
if area is None:
data[:,:k][D] = modification(data[:,:k][D])
else:
(c1, r1), (c2, r2) = area
for i in range(r1, r2+1):
l, r = i*h+c1, i*h+c2+1
data[l:r,:k][D[l:r]] = modification(data[l:r,:k][D[l:r]])
data = np.reshape(data, (w,h,k))
img = Image.fromarray(np.asarray(np.clip(data, 0, 255), dtype="uint8"), "RGB")
img.save(output)
print("[*] DONE Replace Color")

if __name__ == "__main__":
def modification(color):
return color * [2,0,0]
# return [255,0,0]
replace_corlor("test.jpg",(36,35,30),modification, ((0,0),(400,100)))









share|improve this question











$endgroup$








  • 1




    $begingroup$
    I have no comments on your code, your Python is better than mine. :) But for color modification you could use the distance to the original_color value. The larger this distance (and the closer the distance is to the distance threshold), the less you modify the color. This way, you will get a smoother transition at the edges of the red region.
    $endgroup$
    – Cris Luengo
    Nov 14 '18 at 5:42










  • $begingroup$
    @CrisLuengo Ah good advice!, thank you ^^
    $endgroup$
    – Aries_is_there
    Nov 14 '18 at 5:56










  • $begingroup$
    Couple of points, firstly, it appears that the modification function only works if it operates on vectors, rather than a single pixel, as you're passing that function the whole image at once. In some ways, it is doing most of the work. Secondly, There's a typo in the variable name original_corlor, nothing major, just confused me for a second. I find the contents of the else clause very confusing, partly because of very short variable names.
    $endgroup$
    – gbartonowen
    Jan 30 at 18:18










  • $begingroup$
    @gbartonowen sorry I don't get what you mean "it operates on vectors, rather than a single pixel", there is a area in parameters, if you wanna just change one pixel, for example the first pixel, just set area=((0,0),(1,1)), and about the typo, you are totally right
    $endgroup$
    – Aries_is_there
    Feb 17 at 18:34










  • $begingroup$
    @Aries_is_there The modification function takes a 3D array of pixels, rather than a single pixel, which means you must formulate the function as numpy compatible operators. In this case it works fine but it looks like a happens to work rather than is meant to work like this
    $endgroup$
    – gbartonowen
    Feb 19 at 10:06














10












10








10


3



$begingroup$


This script replaces the red hair in image to black color (replace one color to another)





Three major parts in this script




  • Not just replace color red to black, I hope the output image looks natural, so I will replace the color close to red to black. This "close" is measured by Euclidean distance.


  • And not just replace by black color, user can modify the red color's r, g, b value separately, like add more green.


  • Choose the area to be changed, rather than change the whole picture





Suggestions I am looking for:




  • I did some NumPy practice before, so any suggestions about NumPy are welcome.


  • I think the code to replace target area is not so elegant, I am not quite sure about this part:



    (c1, r1), (c2, r2) = area
    for i in range(r1, r2+1):
    l, r = i*h+c1, i*h+c2+1
    data[l:r,:k][D[l:r]] = modification(data[l:r,:k][D[l:r]])





Full code:



import numpy as np
from PIL import Image
from scipy.spatial.distance import cdist

def replace_corlor(image, original_corlor, modification, area=None, distance=1000, output="new_test.jpg"):
print("[*] START Replace Color")
img = Image.open(image)
data = np.asarray(img, dtype="int32")
w,h,k = data.shape
data = np.reshape(data, (w*h,k))
distMatrix = cdist(data, np.array([original_corlor]))
D = distMatrix<=distance
D = np.reshape(D,w*h)
if area is None:
data[:,:k][D] = modification(data[:,:k][D])
else:
(c1, r1), (c2, r2) = area
for i in range(r1, r2+1):
l, r = i*h+c1, i*h+c2+1
data[l:r,:k][D[l:r]] = modification(data[l:r,:k][D[l:r]])
data = np.reshape(data, (w,h,k))
img = Image.fromarray(np.asarray(np.clip(data, 0, 255), dtype="uint8"), "RGB")
img.save(output)
print("[*] DONE Replace Color")

if __name__ == "__main__":
def modification(color):
return color * [2,0,0]
# return [255,0,0]
replace_corlor("test.jpg",(36,35,30),modification, ((0,0),(400,100)))









share|improve this question











$endgroup$




This script replaces the red hair in image to black color (replace one color to another)





Three major parts in this script




  • Not just replace color red to black, I hope the output image looks natural, so I will replace the color close to red to black. This "close" is measured by Euclidean distance.


  • And not just replace by black color, user can modify the red color's r, g, b value separately, like add more green.


  • Choose the area to be changed, rather than change the whole picture





Suggestions I am looking for:




  • I did some NumPy practice before, so any suggestions about NumPy are welcome.


  • I think the code to replace target area is not so elegant, I am not quite sure about this part:



    (c1, r1), (c2, r2) = area
    for i in range(r1, r2+1):
    l, r = i*h+c1, i*h+c2+1
    data[l:r,:k][D[l:r]] = modification(data[l:r,:k][D[l:r]])





Full code:



import numpy as np
from PIL import Image
from scipy.spatial.distance import cdist

def replace_corlor(image, original_corlor, modification, area=None, distance=1000, output="new_test.jpg"):
print("[*] START Replace Color")
img = Image.open(image)
data = np.asarray(img, dtype="int32")
w,h,k = data.shape
data = np.reshape(data, (w*h,k))
distMatrix = cdist(data, np.array([original_corlor]))
D = distMatrix<=distance
D = np.reshape(D,w*h)
if area is None:
data[:,:k][D] = modification(data[:,:k][D])
else:
(c1, r1), (c2, r2) = area
for i in range(r1, r2+1):
l, r = i*h+c1, i*h+c2+1
data[l:r,:k][D[l:r]] = modification(data[l:r,:k][D[l:r]])
data = np.reshape(data, (w,h,k))
img = Image.fromarray(np.asarray(np.clip(data, 0, 255), dtype="uint8"), "RGB")
img.save(output)
print("[*] DONE Replace Color")

if __name__ == "__main__":
def modification(color):
return color * [2,0,0]
# return [255,0,0]
replace_corlor("test.jpg",(36,35,30),modification, ((0,0),(400,100)))






python python-3.x image numpy






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 '18 at 5:32









Cris Luengo

2,544319




2,544319










asked Nov 11 '18 at 10:27









Aries_is_thereAries_is_there

692212




692212








  • 1




    $begingroup$
    I have no comments on your code, your Python is better than mine. :) But for color modification you could use the distance to the original_color value. The larger this distance (and the closer the distance is to the distance threshold), the less you modify the color. This way, you will get a smoother transition at the edges of the red region.
    $endgroup$
    – Cris Luengo
    Nov 14 '18 at 5:42










  • $begingroup$
    @CrisLuengo Ah good advice!, thank you ^^
    $endgroup$
    – Aries_is_there
    Nov 14 '18 at 5:56










  • $begingroup$
    Couple of points, firstly, it appears that the modification function only works if it operates on vectors, rather than a single pixel, as you're passing that function the whole image at once. In some ways, it is doing most of the work. Secondly, There's a typo in the variable name original_corlor, nothing major, just confused me for a second. I find the contents of the else clause very confusing, partly because of very short variable names.
    $endgroup$
    – gbartonowen
    Jan 30 at 18:18










  • $begingroup$
    @gbartonowen sorry I don't get what you mean "it operates on vectors, rather than a single pixel", there is a area in parameters, if you wanna just change one pixel, for example the first pixel, just set area=((0,0),(1,1)), and about the typo, you are totally right
    $endgroup$
    – Aries_is_there
    Feb 17 at 18:34










  • $begingroup$
    @Aries_is_there The modification function takes a 3D array of pixels, rather than a single pixel, which means you must formulate the function as numpy compatible operators. In this case it works fine but it looks like a happens to work rather than is meant to work like this
    $endgroup$
    – gbartonowen
    Feb 19 at 10:06














  • 1




    $begingroup$
    I have no comments on your code, your Python is better than mine. :) But for color modification you could use the distance to the original_color value. The larger this distance (and the closer the distance is to the distance threshold), the less you modify the color. This way, you will get a smoother transition at the edges of the red region.
    $endgroup$
    – Cris Luengo
    Nov 14 '18 at 5:42










  • $begingroup$
    @CrisLuengo Ah good advice!, thank you ^^
    $endgroup$
    – Aries_is_there
    Nov 14 '18 at 5:56










  • $begingroup$
    Couple of points, firstly, it appears that the modification function only works if it operates on vectors, rather than a single pixel, as you're passing that function the whole image at once. In some ways, it is doing most of the work. Secondly, There's a typo in the variable name original_corlor, nothing major, just confused me for a second. I find the contents of the else clause very confusing, partly because of very short variable names.
    $endgroup$
    – gbartonowen
    Jan 30 at 18:18










  • $begingroup$
    @gbartonowen sorry I don't get what you mean "it operates on vectors, rather than a single pixel", there is a area in parameters, if you wanna just change one pixel, for example the first pixel, just set area=((0,0),(1,1)), and about the typo, you are totally right
    $endgroup$
    – Aries_is_there
    Feb 17 at 18:34










  • $begingroup$
    @Aries_is_there The modification function takes a 3D array of pixels, rather than a single pixel, which means you must formulate the function as numpy compatible operators. In this case it works fine but it looks like a happens to work rather than is meant to work like this
    $endgroup$
    – gbartonowen
    Feb 19 at 10:06








1




1




$begingroup$
I have no comments on your code, your Python is better than mine. :) But for color modification you could use the distance to the original_color value. The larger this distance (and the closer the distance is to the distance threshold), the less you modify the color. This way, you will get a smoother transition at the edges of the red region.
$endgroup$
– Cris Luengo
Nov 14 '18 at 5:42




$begingroup$
I have no comments on your code, your Python is better than mine. :) But for color modification you could use the distance to the original_color value. The larger this distance (and the closer the distance is to the distance threshold), the less you modify the color. This way, you will get a smoother transition at the edges of the red region.
$endgroup$
– Cris Luengo
Nov 14 '18 at 5:42












$begingroup$
@CrisLuengo Ah good advice!, thank you ^^
$endgroup$
– Aries_is_there
Nov 14 '18 at 5:56




$begingroup$
@CrisLuengo Ah good advice!, thank you ^^
$endgroup$
– Aries_is_there
Nov 14 '18 at 5:56












$begingroup$
Couple of points, firstly, it appears that the modification function only works if it operates on vectors, rather than a single pixel, as you're passing that function the whole image at once. In some ways, it is doing most of the work. Secondly, There's a typo in the variable name original_corlor, nothing major, just confused me for a second. I find the contents of the else clause very confusing, partly because of very short variable names.
$endgroup$
– gbartonowen
Jan 30 at 18:18




$begingroup$
Couple of points, firstly, it appears that the modification function only works if it operates on vectors, rather than a single pixel, as you're passing that function the whole image at once. In some ways, it is doing most of the work. Secondly, There's a typo in the variable name original_corlor, nothing major, just confused me for a second. I find the contents of the else clause very confusing, partly because of very short variable names.
$endgroup$
– gbartonowen
Jan 30 at 18:18












$begingroup$
@gbartonowen sorry I don't get what you mean "it operates on vectors, rather than a single pixel", there is a area in parameters, if you wanna just change one pixel, for example the first pixel, just set area=((0,0),(1,1)), and about the typo, you are totally right
$endgroup$
– Aries_is_there
Feb 17 at 18:34




$begingroup$
@gbartonowen sorry I don't get what you mean "it operates on vectors, rather than a single pixel", there is a area in parameters, if you wanna just change one pixel, for example the first pixel, just set area=((0,0),(1,1)), and about the typo, you are totally right
$endgroup$
– Aries_is_there
Feb 17 at 18:34












$begingroup$
@Aries_is_there The modification function takes a 3D array of pixels, rather than a single pixel, which means you must formulate the function as numpy compatible operators. In this case it works fine but it looks like a happens to work rather than is meant to work like this
$endgroup$
– gbartonowen
Feb 19 at 10:06




$begingroup$
@Aries_is_there The modification function takes a 3D array of pixels, rather than a single pixel, which means you must formulate the function as numpy compatible operators. In this case it works fine but it looks like a happens to work rather than is meant to work like this
$endgroup$
– gbartonowen
Feb 19 at 10:06










1 Answer
1






active

oldest

votes


















0












$begingroup$

Nice code.
Let's look at the function signatures.
As gbartonowen noted, two typos on corlor for color.
The keyword defaults are lovely,
thank you for appropriately dealing with a magic number, and defaulting the filespec.
Lots of keywords will lead to a somewhat long signature, though, as reported by $ flake8:



E501 line too long (106 > 79 characters)


Recommend you always run such a linter before sharing code.
And heed the linter's advice.
In the same vein we see things like PEP-8 wants spaces in the w, h, k assignment,
or (w * h, k) expression.
And, this being python rather than java,
snake-case identifiers of d and dist_matrix would be much more appropriate.
Python convention says the Gentle Reader should expect D to be a class.
(Yes, I know this clashes with conventions of the mathematical community,
something had to give. Ok, on to more substantive comments.)



An identifier of data is always on the vague side,
it's a bit like naming your variable the_thing.
Yes, it's accurate, but often it could be a little more informative.
Consider a rename along these lines:



    img = np.asarray(Image.open(image), dtype='int32')


(Hmmm, as I look at that, maybe we'd like identifiers of in_file and out_file?)



The cdist() call, which defaults to Euclidean, is pretty interesting,
since RGB is not a perceptually uniform color scheme.
Consider mapping to Lab* colorspace and using that for comparisons.



It is slightly tricky for a naive caller to correctly pass in area,
so it warrants mention in the docstring you're going to write,
or at least in a comment.
Similarly for the modification signature.
Consider raising an error if c1 < c2 or r1 < r2 does not hold.



The l, r identifiers are well chosen,
and I eventually puzzled out their meaning,
but I wouldn't mind a comment mentioning "left, right",
as I kept thinking in terms of "row".
I also wouldn't mind seeing comments explaining the need for each reshape().



If speed is a concern, then figuring out how to get modification()
to broadcast values to a sub-rectangle would be the thing to focus on.



The saturating aspect of [2, 0, 0] is slightly surprising,
please comment on it, and how it deliberately interacts with clip().
Also, the list is not pythonic, this should definitely be the tuple (2, 0, 0).
A more descriptive name, perhaps red_modification, would be appropriate.



Protecting def modification so import won't see it
kind of make sense, but is a little weird.
You don't want that example to be part of your public API, that's fine.
But consider using def _modification in the usual way,
so the __main__ clause is just a one-liner.



Well, OK, two lines, as the magic tuple (36, 35, 30)
needs a name like dark_gray.



Looks good, ship it!






share|improve this answer











$endgroup$














    Your Answer





    StackExchange.ifUsing("editor", function () {
    return StackExchange.using("mathjaxEditing", function () {
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    });
    });
    }, "mathjax-editing");

    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207415%2freplace-color-in-image-measured-by-euclidean-distance%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0












    $begingroup$

    Nice code.
    Let's look at the function signatures.
    As gbartonowen noted, two typos on corlor for color.
    The keyword defaults are lovely,
    thank you for appropriately dealing with a magic number, and defaulting the filespec.
    Lots of keywords will lead to a somewhat long signature, though, as reported by $ flake8:



    E501 line too long (106 > 79 characters)


    Recommend you always run such a linter before sharing code.
    And heed the linter's advice.
    In the same vein we see things like PEP-8 wants spaces in the w, h, k assignment,
    or (w * h, k) expression.
    And, this being python rather than java,
    snake-case identifiers of d and dist_matrix would be much more appropriate.
    Python convention says the Gentle Reader should expect D to be a class.
    (Yes, I know this clashes with conventions of the mathematical community,
    something had to give. Ok, on to more substantive comments.)



    An identifier of data is always on the vague side,
    it's a bit like naming your variable the_thing.
    Yes, it's accurate, but often it could be a little more informative.
    Consider a rename along these lines:



        img = np.asarray(Image.open(image), dtype='int32')


    (Hmmm, as I look at that, maybe we'd like identifiers of in_file and out_file?)



    The cdist() call, which defaults to Euclidean, is pretty interesting,
    since RGB is not a perceptually uniform color scheme.
    Consider mapping to Lab* colorspace and using that for comparisons.



    It is slightly tricky for a naive caller to correctly pass in area,
    so it warrants mention in the docstring you're going to write,
    or at least in a comment.
    Similarly for the modification signature.
    Consider raising an error if c1 < c2 or r1 < r2 does not hold.



    The l, r identifiers are well chosen,
    and I eventually puzzled out their meaning,
    but I wouldn't mind a comment mentioning "left, right",
    as I kept thinking in terms of "row".
    I also wouldn't mind seeing comments explaining the need for each reshape().



    If speed is a concern, then figuring out how to get modification()
    to broadcast values to a sub-rectangle would be the thing to focus on.



    The saturating aspect of [2, 0, 0] is slightly surprising,
    please comment on it, and how it deliberately interacts with clip().
    Also, the list is not pythonic, this should definitely be the tuple (2, 0, 0).
    A more descriptive name, perhaps red_modification, would be appropriate.



    Protecting def modification so import won't see it
    kind of make sense, but is a little weird.
    You don't want that example to be part of your public API, that's fine.
    But consider using def _modification in the usual way,
    so the __main__ clause is just a one-liner.



    Well, OK, two lines, as the magic tuple (36, 35, 30)
    needs a name like dark_gray.



    Looks good, ship it!






    share|improve this answer











    $endgroup$


















      0












      $begingroup$

      Nice code.
      Let's look at the function signatures.
      As gbartonowen noted, two typos on corlor for color.
      The keyword defaults are lovely,
      thank you for appropriately dealing with a magic number, and defaulting the filespec.
      Lots of keywords will lead to a somewhat long signature, though, as reported by $ flake8:



      E501 line too long (106 > 79 characters)


      Recommend you always run such a linter before sharing code.
      And heed the linter's advice.
      In the same vein we see things like PEP-8 wants spaces in the w, h, k assignment,
      or (w * h, k) expression.
      And, this being python rather than java,
      snake-case identifiers of d and dist_matrix would be much more appropriate.
      Python convention says the Gentle Reader should expect D to be a class.
      (Yes, I know this clashes with conventions of the mathematical community,
      something had to give. Ok, on to more substantive comments.)



      An identifier of data is always on the vague side,
      it's a bit like naming your variable the_thing.
      Yes, it's accurate, but often it could be a little more informative.
      Consider a rename along these lines:



          img = np.asarray(Image.open(image), dtype='int32')


      (Hmmm, as I look at that, maybe we'd like identifiers of in_file and out_file?)



      The cdist() call, which defaults to Euclidean, is pretty interesting,
      since RGB is not a perceptually uniform color scheme.
      Consider mapping to Lab* colorspace and using that for comparisons.



      It is slightly tricky for a naive caller to correctly pass in area,
      so it warrants mention in the docstring you're going to write,
      or at least in a comment.
      Similarly for the modification signature.
      Consider raising an error if c1 < c2 or r1 < r2 does not hold.



      The l, r identifiers are well chosen,
      and I eventually puzzled out their meaning,
      but I wouldn't mind a comment mentioning "left, right",
      as I kept thinking in terms of "row".
      I also wouldn't mind seeing comments explaining the need for each reshape().



      If speed is a concern, then figuring out how to get modification()
      to broadcast values to a sub-rectangle would be the thing to focus on.



      The saturating aspect of [2, 0, 0] is slightly surprising,
      please comment on it, and how it deliberately interacts with clip().
      Also, the list is not pythonic, this should definitely be the tuple (2, 0, 0).
      A more descriptive name, perhaps red_modification, would be appropriate.



      Protecting def modification so import won't see it
      kind of make sense, but is a little weird.
      You don't want that example to be part of your public API, that's fine.
      But consider using def _modification in the usual way,
      so the __main__ clause is just a one-liner.



      Well, OK, two lines, as the magic tuple (36, 35, 30)
      needs a name like dark_gray.



      Looks good, ship it!






      share|improve this answer











      $endgroup$
















        0












        0








        0





        $begingroup$

        Nice code.
        Let's look at the function signatures.
        As gbartonowen noted, two typos on corlor for color.
        The keyword defaults are lovely,
        thank you for appropriately dealing with a magic number, and defaulting the filespec.
        Lots of keywords will lead to a somewhat long signature, though, as reported by $ flake8:



        E501 line too long (106 > 79 characters)


        Recommend you always run such a linter before sharing code.
        And heed the linter's advice.
        In the same vein we see things like PEP-8 wants spaces in the w, h, k assignment,
        or (w * h, k) expression.
        And, this being python rather than java,
        snake-case identifiers of d and dist_matrix would be much more appropriate.
        Python convention says the Gentle Reader should expect D to be a class.
        (Yes, I know this clashes with conventions of the mathematical community,
        something had to give. Ok, on to more substantive comments.)



        An identifier of data is always on the vague side,
        it's a bit like naming your variable the_thing.
        Yes, it's accurate, but often it could be a little more informative.
        Consider a rename along these lines:



            img = np.asarray(Image.open(image), dtype='int32')


        (Hmmm, as I look at that, maybe we'd like identifiers of in_file and out_file?)



        The cdist() call, which defaults to Euclidean, is pretty interesting,
        since RGB is not a perceptually uniform color scheme.
        Consider mapping to Lab* colorspace and using that for comparisons.



        It is slightly tricky for a naive caller to correctly pass in area,
        so it warrants mention in the docstring you're going to write,
        or at least in a comment.
        Similarly for the modification signature.
        Consider raising an error if c1 < c2 or r1 < r2 does not hold.



        The l, r identifiers are well chosen,
        and I eventually puzzled out their meaning,
        but I wouldn't mind a comment mentioning "left, right",
        as I kept thinking in terms of "row".
        I also wouldn't mind seeing comments explaining the need for each reshape().



        If speed is a concern, then figuring out how to get modification()
        to broadcast values to a sub-rectangle would be the thing to focus on.



        The saturating aspect of [2, 0, 0] is slightly surprising,
        please comment on it, and how it deliberately interacts with clip().
        Also, the list is not pythonic, this should definitely be the tuple (2, 0, 0).
        A more descriptive name, perhaps red_modification, would be appropriate.



        Protecting def modification so import won't see it
        kind of make sense, but is a little weird.
        You don't want that example to be part of your public API, that's fine.
        But consider using def _modification in the usual way,
        so the __main__ clause is just a one-liner.



        Well, OK, two lines, as the magic tuple (36, 35, 30)
        needs a name like dark_gray.



        Looks good, ship it!






        share|improve this answer











        $endgroup$



        Nice code.
        Let's look at the function signatures.
        As gbartonowen noted, two typos on corlor for color.
        The keyword defaults are lovely,
        thank you for appropriately dealing with a magic number, and defaulting the filespec.
        Lots of keywords will lead to a somewhat long signature, though, as reported by $ flake8:



        E501 line too long (106 > 79 characters)


        Recommend you always run such a linter before sharing code.
        And heed the linter's advice.
        In the same vein we see things like PEP-8 wants spaces in the w, h, k assignment,
        or (w * h, k) expression.
        And, this being python rather than java,
        snake-case identifiers of d and dist_matrix would be much more appropriate.
        Python convention says the Gentle Reader should expect D to be a class.
        (Yes, I know this clashes with conventions of the mathematical community,
        something had to give. Ok, on to more substantive comments.)



        An identifier of data is always on the vague side,
        it's a bit like naming your variable the_thing.
        Yes, it's accurate, but often it could be a little more informative.
        Consider a rename along these lines:



            img = np.asarray(Image.open(image), dtype='int32')


        (Hmmm, as I look at that, maybe we'd like identifiers of in_file and out_file?)



        The cdist() call, which defaults to Euclidean, is pretty interesting,
        since RGB is not a perceptually uniform color scheme.
        Consider mapping to Lab* colorspace and using that for comparisons.



        It is slightly tricky for a naive caller to correctly pass in area,
        so it warrants mention in the docstring you're going to write,
        or at least in a comment.
        Similarly for the modification signature.
        Consider raising an error if c1 < c2 or r1 < r2 does not hold.



        The l, r identifiers are well chosen,
        and I eventually puzzled out their meaning,
        but I wouldn't mind a comment mentioning "left, right",
        as I kept thinking in terms of "row".
        I also wouldn't mind seeing comments explaining the need for each reshape().



        If speed is a concern, then figuring out how to get modification()
        to broadcast values to a sub-rectangle would be the thing to focus on.



        The saturating aspect of [2, 0, 0] is slightly surprising,
        please comment on it, and how it deliberately interacts with clip().
        Also, the list is not pythonic, this should definitely be the tuple (2, 0, 0).
        A more descriptive name, perhaps red_modification, would be appropriate.



        Protecting def modification so import won't see it
        kind of make sense, but is a little weird.
        You don't want that example to be part of your public API, that's fine.
        But consider using def _modification in the usual way,
        so the __main__ clause is just a one-liner.



        Well, OK, two lines, as the magic tuple (36, 35, 30)
        needs a name like dark_gray.



        Looks good, ship it!







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 21 mins ago

























        answered 28 mins ago









        J_HJ_H

        4,487130




        4,487130






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207415%2freplace-color-in-image-measured-by-euclidean-distance%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Costa Masnaga

            Fotorealismo

            Sidney Franklin