Transforming 3 channel image to greyscale 1 channel

Bunki_Shimomura: <p>Hi. I’m facing a problem transforming RGB image into greyscale image.</p>
<p>I want to make the channel of image from 3 to 1, and the image came out as 1 channel but green-ish color, not greyscale.</p>
<p>Lines of codes commented out in class MyNormalize is what I have tried.</p>
<p>Could anybody suggest a way to transform this RGB image into greyscale&amp;1 channel image?</p>
<p>By the way, in test(test_loader) method, variable image includes 16 images, but does it process each of the 16 images?<br>
I don’t quite get how this process is working <img src="https://discuss.pytorch.org/images/emoji/apple/frowning.png?v=9" title=":frowning:" class="emoji" alt=":frowning:"></p>
<p>I appreciate your cooperation. Thank you!</p>
<pre><code class="lang-auto">imgDataset = MyDataset(csv_file_path, ROOT_DIR, transform=transforms.Compose([
    transforms.Resize(50),
    transforms.ToTensor(),
    MyNormalize()
    ]))

class MyNormalize:
    def __call__(self, image):
        shape = image.shape

        '''
        trans1 = transforms.ToPILImage()
        trans2 = transforms.ToTensor()
        image = trans1(image)
        image = image.convert('L')
        image = trans2(image)
        '''
        
        #image = tv.transforms.functional.to_grayscale(trans1(image), num_output_channels=1)

        #image = 0.299 * image[:, :, 0] + 0.587 * image[:, :, 1] + 0.114 * image[:, :, 2]
        #image = (image - np.mean(image.numpy()))/np.std(image.numpy())*16+64
        
        return image

def test(test_loader):
    correct = 0
    test_loss = 0
    model.eval()
    with torch.no_grad():
        for (image, label) in test_loader:
            image, label = Variable(image.float()), Variable(label)
            print("image: ", type(image))
            #image:  &lt;class 'torch.Tensor'&gt;
            print("image: ", image.shape)
            #image:  torch.Size([16, 1, 50, 50])
            print("image[0]: ", type(image[0]))
            #image:  &lt;class 'torch.Tensor'&gt;
            print("image[0]: ", image[0].shape)
            #image:  torch.Size([1, 50, 50])
            print("image[0][0]: ", type(image[0][0]))
            #image:  &lt;class 'torch.Tensor'&gt;
            print("image[0][0]: ", image[0][0].shape)
            #image:  torch.Size([50, 50])

            output = model(image)
            test_loss += criterion(output, label).data
            pred = output.data.max(1, keepdim=True)[1]
            correct += pred.eq(label.data.view_as(pred)).long().cpu().sum()

    test_loss /= len(test_loader.dataset)
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))
</code></pre>

ptrblck: <p>How are you visualizing the image?<br>
A single channel image shouldn’t have any color, so your current library used to plot the image might just create the green color.</p>

Bunki_Shimomura: <p>Thank you for the reply.</p>
<p>I’m using pillow to visualize the image.<br>
Do you mean my images as tensor are already in greyscale but pillow visualized image with green?</p>
<p>Trained model seems not to be classifying the images correctly, so I’m guessing if there is any relationship with color.</p>

ptrblck: <p>Could you post the code you are using to visualize the image?</p>
<p>A single channel image should not have any color, but the library might use some colormap to plot it.<br>
The same applies e.g. for <code>matplotlib</code> and a float image:</p>
<pre><code class="lang-python">import matplotlib.pyplot as plt
import numpy as np

img = np.random.randn(100, 100)
plt.imshow(img)  # Colored output

# plt.imshow(img, cmap='gray')  # Gray output
</code></pre>

Bunki_Shimomura: <p>Sorry for the late reply <img src="https://discuss.pytorch.org/images/emoji/apple/frowning.png?v=9" title=":frowning:" class="emoji" alt=":frowning:"></p>
<p>Below is my code.</p>
<p>I tried using .numpy() but imgDataset[0][0] was not the right shape for image data.</p>
<pre><code class="lang-auto">import matplotlib.pyplot as plt
from PIL import Image

print(imgDataset[0][0].shape)
#torch.Size([1, 50, 50])
print(imgDataset[0][0].size)
#&lt;built-in method size of Tensor object at 0x1c2cc82360&gt;
print(imgDataset[0][0].dtype)
#torch.float32

trans = transforms.ToPILImage()
plt.imshow(trans(imgDataset[0][0]))
plt.show()
</code></pre>

mattdeitke: <p>If you are using PIL, you can use</p>
<pre><code class="lang-auto">trans.convert('L')
</code></pre>
<p>which will convert the RGB image into greyscale (more <a href="https://pillow.readthedocs.io/en/4.2.x/reference/Image.html#PIL.Image.Image.convert" rel="nofollow noopener">here</a>). You can now plot the image using</p>
<pre><code class="lang-auto">plt.imshow(trans)
</code></pre>
<p>If that gives non-greyscaled colors, you can force the colormap to be black and white using matplotlib’s binary colormap by writing:</p>
<pre><code class="lang-auto">plt.imshow(trans, cmap=plt.cm.binary)
</code></pre>
<p>Here, I’m assuming <code>type(trans)</code> is <code>&lt;class 'PIL.Image.Image'&gt;</code>.</p>

Bunki_Shimomura: <p>Thank you very much!<br>
Using binary colormap, the image came out in greyscale.</p>
<p>However, the problem is that the image does not seem to be processed as greyscale in train function.</p>
<p>How can I convert the image properly in greyscale when I load data from dataset??<br>
Transformation code is shown in the first post.</p>

mattdeitke: <p>Using the CIFAR10 dataset, for example, you can use the Grayscale transform.</p>
<pre><code class="lang-auto">import torchvision.transforms as transforms
import torchvision.datasets as datasets

trainset = datasets.CIFAR10(root='./data', train=True, download=True,
    transform=transforms.Grayscale(num_output_channels=1))
</code></pre>
<p>To confirm, you could call <code>trainset[0][0].size</code>, which gives back <code>(32, 32)</code> (with 1 channel). Also, you could again plot the data using:</p>
<pre><code class="lang-auto">plt.imshow(trainset[0][0], cmap=plt.cm.binary)
</code></pre>

Bunki_Shimomura: <p>Thank you <a class="mention" href="/u/mattdeitke">@mattdeitke</a></p>
<p>transforms.Grayscale ran without errors, but it gave [1, 50, 50] shape, and showed green image without cmap=plt.cm.binary option.</p>
<p>Could it be a problem with the original dataset?</p>
<pre><code class="lang-auto">class MyDataset(Dataset):

    def __init__(self, csv_file_path, root_dir, transform=None):
        self.image_dataframe = pd.read_csv(csv_file_path)
        self.root_dir = root_dir
        self.transform = transform

    def __len__(self):
        return len(self.image_dataframe)

    def __getitem__(self, idx):
        label = self.image_dataframe.iat[idx, LABEL_IDX]
        img_name = os.path.join(self.root_dir, 'data', 'load_data', self.image_dataframe.iat[idx, IMG_IDX]) 
        image = Image.open(img_name)
        if self.transform:
            image = self.transform(image)

        return image, label

imgDataset = MyDataset(csv_file_path, ROOT_DIR, transform=transforms.Compose([
    transforms.Grayscale(num_output_channels=1),
    transforms.Resize(50),
    transforms.ToTensor(),
    MyNormalize()
    ]))

print(imgDataset[0][0].size)
#&lt;built-in method size of Tensor object at 0x1c2fce0708&gt;
print(imgDataset[0][0].shape)
#torch.Size([1, 50, 50])
</code></pre>

Bunki_Shimomura: <p>Thank you so very much for all your cooperation!!<br>
Problem solved!!</p>
<p>Shape of the tensor which came out as [1, 50, 50] successfully became [50, 50] by first loading the image with OpenCV and transforming into PIL to modify.</p>
<p>As <a class="mention" href="/u/mattdeitke">@mattdeitke</a> and <a class="mention" href="/u/ptrblck">@ptrblck</a> said, green-ish visualization of the image was a matter of option. Using plt.gray() solved the problem.</p>
<pre><code class="lang-auto">
class MyDataset(Dataset):
    def __getitem__(self, idx):
        label = self.image_dataframe.iat[idx, LABEL_IDX]
        img_name = os.path.join(self.root_dir, 'data', 'load_data', self.image_dataframe.iat[idx, IMG_IDX]) 
        image = cv2.imread(img_name)
        if self.transform:
            im = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            im2 = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
            image = Image.fromarray(im2)
            image = self.transform(image)


trans = transforms.ToPILImage()
plt.imshow(trans(imgDataset[0][0]))
plt.gray()
plt.show()
</code></pre>