Applying a hreshold on an Image

Tm4: <p>I have an image and I want to make the background totally equal to zero. In other words, the strategy that came to my mind was that using torch.clamp and setting the minimum value equal to the minimum value of the image. But I faced with the following error.</p>
<pre><code class="lang-auto">    smap = torch.clamp(torch.from_numpy(smap), min=torch.min(smap)).numpy()


</code></pre>
<p>Error: <code>TypeError: min(): argument 'input' (position 1) must be Tensor, not numpy.ndarray</code></p>
<p><img src="https://discuss.pytorch.org/uploads/default/original/3X/7/3/73e31cd2aa2f73b49ef5789b1f1a06d468677dd7.png" alt="0013" data-base62-sha1="gxbuJ0I7NIgfNSiL94qORFUkHxJ" width="224" height="224"></p>
<p>How I can fix that?</p>

J_Johnson: <p>It’s just saying you forgot to apply <code>torch.from_numpy()</code> on the input for <code>min=torch.min(smap)</code>.</p>
<pre><code class="lang-auto">smap = torch.clamp(torch.from_numpy(smap), min=torch.min(torch.from_numpy(smap))).numpy()
</code></pre>

Tm4: <p>Thank you for the answer. Unfortunately , the output is like the previous one and nothing has been changed. Do you have any suggestion that how I  can fix the problem.</p>

J_Johnson: <aside class="quote no-group" data-username="J_Johnson" data-post="2" data-topic="174335">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/j_johnson/48/55494_2.png" class="avatar"> J_Johnson:</div>
<blockquote>
<p><code>smap = torch.clamp(torch.from_numpy(smap), min=torch.min(torch.from_numpy(smap))).numpy()</code></p>
</blockquote>
</aside>
<p><a class="mention" href="/u/tm4">@Tm4</a> Worked for me:</p>
<pre><code class="lang-auto">import torch
import numpy as np

smap = np.random.rand(3,2)
smap = torch.clamp(torch.from_numpy(smap), min=torch.min(torch.from_numpy(smap))).numpy()

print(smap)
</code></pre>
<blockquote>
<p>[[0.13507522 0.95144342]<br>
[0.88192039 0.24267395]<br>
[0.4150879  0.65108563]]</p>
</blockquote>

Tm4: <p>Thanks for the answer, in other words, I meant that although I used this strategy, the output does not contain a black background like the following image as I expected:</p>
<p><img src="https://discuss.pytorch.org/uploads/default/original/3X/3/c/3c18286a330504f6a8afff9ee8d0acb7f07c550e.png" alt="0003" data-base62-sha1="8zCpbwXOjXOsa8ZQPekO6TGWe9U" width="224" height="224"></p>
<p>Do you know which strategy I should use to apply such thresholding to have such image with a black background?</p>

J_Johnson: <p>The normalization function is (image - min)/(max - min). In this case, sounds like you want a clamp to set the minimum value, and then normalize to that range.</p>
<pre><code class="lang-auto">import torch
from matplotlib import pyplot as plt

#Example 1: Normalization only to lowest value
dummy_image=torch.rand(3, 16, 16)
plt.imshow(dummy_image.permute(1,2,0))
plt.show()
min_val = dummy_image.min()

adjusted_image = (dummy_image-min_val)/(1-min_val)
plt.imshow(adjusted_image.permute(1,2,0))
plt.show()

#Example 2: Clamped value, and normalization to that value
dummy_image=torch.rand(3, 16, 16)
plt.imshow(dummy_image.permute(1,2,0))
plt.show()

clamped_val = 0.5

dummy_image[dummy_image&lt;clamped_val]=0.5
min_val = dummy_image.min()
adjusted_image = (dummy_image-min_val)/(1-min_val)
plt.imshow(adjusted_image.permute(1,2,0))
plt.show()
</code></pre>

Tm4: <p>Thanks for the solution but unfortunately when I apply each of two examples, I face the following error in another line of my script:</p>
<pre><code class="lang-auto">Exception has occurred: error
OpenCV(4.6.0) /io/opencv/modules/imgproc/src/colormap.cpp:736: error: (-5:Bad argument) cv::ColorMap only supports source images of type CV_8UC1 or CV_8UC3 in function 'operator()'
  File "/test.py", line 140, in main
    img = cv2.applyColorMap(frames_mask[i],cv2.COLORMAP_HOT)
</code></pre>
<p>How I can fix the problem?</p>

J_Johnson: <p>What kind of object are you feeding to it and what are the dims? The example explicitly used a Pytorch tensor object with all values between 0 and 1 with dims 3, 16, 16.</p>

Tm4: <p>I use this <a href="https://github.com/perceivelab/hd2s/blob/master/test.py" rel="noopener nofollow ugc">script</a> for generating the maps. But I modified the code by changing <code>fromVideo=True</code> and also <code>image_size=(224, 224)</code>.The code reads videos (*.AVI) and split videos to frames that the size of the frames is(224, 224). How I can fix the problem?</p>

Tm4: <p>Moreover, the <code>smap</code> that I want to apply such operation on that has the shape of (224,224).</p>

J_Johnson: <p>In order to view an image in imshow, it needs to have height, width and channels.</p>

TzviNoy: <p>If you need just this specific image I would try:</p>
<pre><code class="lang-auto">result = torch.where(smap &gt; threshold, smap, 0)
</code></pre>
<p>and look for the threshold that give the expected result.</p>
<p>To find the right threshold, plotting the histogram of the image would be helpful</p>

Tm4: <p>It is the output map of a saliency detection method and it doesn’t contain any channel. The output for <code>smap.shape</code> is (224,224)</p>

Tm4: <p>Thanks for the answer, but I want to apply the solution on different images of this kind and they would require different values for threshold. Moreover, when I use your answer, I see the following error:</p>
<pre><code class="lang-auto">Exception has occurred: TypeError
where() received an invalid combination of arguments - got (numpy.ndarray, numpy.ndarray, int), but expected one of:
 * (Tensor condition)
 * (Tensor condition, Tensor input, Tensor other, *, Tensor out)
 * (Tensor condition, Number self, Tensor other)
      didn't match because some of the arguments have invalid types: (e[31;1mnumpy.ndarraye[0m, e[31;1mnumpy.ndarraye[0m, e[31;1minte[0m)
 * (Tensor condition, Tensor input, Number other)
      didn't match because some of the arguments have invalid types: (e[31;1mnumpy.ndarraye[0m, e[31;1mnumpy.ndarraye[0m, e[31;1minte[0m)
 * (Tensor condition, Number self, Number other)
      didn't match because some of the arguments have invalid types: (e[31;1mnumpy.ndarraye[0m, e[31;1mnumpy.ndarraye[0m, e[31;1minte[0m)
</code></pre>

J_Johnson: <p>There are always channels, even if the channels are just 1. Otherwise, it would contain no data. You can change:</p>
<pre><code class="lang-auto">plt.imshow(adjusted_image.unsqueeze(0).permute(1,2,0))
</code></pre>

Tm4: <p>Thanks for the answer, because I do not need to show it and I want to save it using the following command:</p>
<pre><code class="lang-auto">cv2.imwrite(os.path.join(frames_path, '%04d.png'%(idx+1)), smap)
</code></pre>
<p>when I use your solution II receive the <a href="https://discuss.pytorch.org/t/applying-a-hreshold-on-an-image/174335/7">aforementioned error</a>. Any idea?</p>

J_Johnson: <p>The solution provided is purely in PyTorch. If you want to use that tensor elsewhere, you’ll need to offload it to NumPy with:</p>
<pre><code class="lang-auto">numpy_object = tensor_object.numpy()
</code></pre>

TzviNoy: <p>You actually need no PyTorch for the solution. NumPy will work as well:</p>
<pre><code class="lang-auto">np.where(smap &gt; threshold, smap, np.zeros_like(smap))
</code></pre>
<p>But as you mentioned - it is irrelevant for threshold that is changing</p>