简体   繁体   English

Python Opencv - 无法更改图片的像素值

[英]Python Opencv - Cannot change pixel value of a picture

Need to change the white pixels to black and black pixels to white of the picture given below需要将下面给出的图片的白色像素更改为黑色,将黑色像素更改为白色在此处输入图片说明

    import cv2

    img=cv2.imread("cvlogo.png")

A basic opencv logo with white background and resized the picture to a fixed known size带有白色背景的基本 opencv 徽标并将图片调整为固定的已知大小

    img=cv2.resize(img, (300,300))#(width,height)


    row,col=0,0
    i=0

Now checking each pixel by its row and column positions with for loop现在用 for 循环检查每个像素的行和列位置

If pixel is white, then change it to black or if pixel is black,change it to white.如果像素为白色,则将其更改为黑色;如果像素为黑色,则将其更改为白色。

    for row in range(0,300,1):
        print(row)
        for col in range(0,300,1):
            print(col)
            if img[row,col] is [255,255,255] : #I have used == instead of 'is'..but there is no change 
                img[row,col]=[0,0,0]
            elif img[row,col] is [0,0,0]:
                img[row,col]=[255,255,255]

There is no error in execution but it is not changing the pixel values to black or white respectively.执行中没有错误,但不会将像素值分别更改为黑色或白色。 More over if statement is also not executing..Too much of confusion..更多 if 语句也没有执行..太混乱了..

    cv2.imshow('img',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

I am not very experienced, but I would do it using numpy.where(), which is faster than the loops.我不是很有经验,但我会使用 numpy.where(),它比循环更快。

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Read the image
original_image=cv2.imread("cvlogo.png")
# Not necessary. Make a copy to plot later
img=np.copy(original_image)

#Isolate the areas where the color is black(every channel=0) and white (every channel=255)
black=np.where((img[:,:,0]==0) & (img[:,:,1]==0) & (img[:,:,2]==0))
white=np.where((img[:,:,0]==255) & (img[:,:,1]==255) & (img[:,:,2]==255))

#Turn black pixels to white and vice versa
img[black]=(255,255,255)
img[white]=(0,0,0)

# Plot the images
fig=plt.figure()
ax1 = fig.add_subplot(1,2,1)
ax1.imshow(original_image)
ax1.set_title('Original Image')
ax2 = fig.add_subplot(1,2,2)
ax2.imshow(img)
ax2.set_title('Modified Image')
plt.show()

在此处输入图片说明

I think this should work.我认为这应该有效。 :) (I used numpy just to get width and height values - you dont need this) :)(我使用 numpy 只是为了获取宽度和高度值 - 你不需要这个)

import cv2

img=cv2.imread("cvlogo.png")
img=cv2.resize(img, (300,300))
height, width, channels = img.shape

white = [255,255,255]
black = [0,0,0]

for x in range(0,width):
    for y in range(0,height):
        channels_xy = img[y,x]
        if all(channels_xy == white):    
            img[y,x] = black

        elif all(channels_xy == black):
            img[y,x] = white

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

This is also a method of solving this problem.这也是解决这个问题的一种方法。 CREDITS:ajlaj25学分:ajlaj25

    import cv2


    img=cv2.imread("cvlogo.png")
    img=cv2.resize(img, (300,300))
    height, width, channels = img.shape

    print(height,width,channels)

    for x in range(0,width):
        for y in range(0,height):
            if img[x,y,0] == 255 and img[x,y,1] == 255 and img[x,y,2] == 255:            
                img[x,y,0] = 0
                img[x,y,1] = 0
                img[x,y,2] = 0

            elif img[x,y,0] == 0 and img[x,y,1] == 0 and img[x,y,2] == 0:
                img[x,y,0] = 255
                img[x,y,1] = 255
                img[x,y,2] = 255

img[x,y] denotes the channel values - all three: [ch1,ch2,ch3] - at the x,y coordinates. img[x,y]表示通道值 - 所有三个: [ch1,ch2,ch3] - 在 x,y 坐标处。 img[x,y,0] is the ch1 channel's value at x,y coordinates. img[x,y,0] 是 ch1 通道在 x,y 坐标处的值。 ** **

x and y denotes pixels location not RGB values of pixel .So, img[x,y,0] is the ch1 channel's value at x,y coordinates x 和 y 表示像素位置而不是像素的 RGB 值。所以, img[x,y,0] 是 ch1 通道在 x,y 坐标处的值

** **

    cv2.imshow('Coverted Image',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

A bit late, but I'd like to contribute with another approach to solve this situation.有点晚了,但我想用另一种方法来解决这种情况。 My approach is based on image indexation , which are faster than looping through the image as the approach used in the accept answer.我的方法基于图像索引,这比在接受答案中使用的方法循环遍历图像要快。

I did some time measurement of both codes to illustrate what I just said.我对这两个代码进行了一些时间测量,以说明我刚才所说的内容。 Take a look at the code below:看看下面的代码:

import cv2
from matplotlib import pyplot as plt

# Reading image to be used in the montage, this step is not important
original = cv2.imread('imgs/opencv.png')

# Starting time measurement
e1 = cv2.getTickCount()

# Reading the image
img = cv2.imread('imgs/opencv.png')

# Converting the image to grayscale
imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# Converting the grayscale image into a binary image to get the whole image
ret,imgBinAll = cv2.threshold(imgGray,175,255,cv2.THRESH_BINARY)

# Converting the grayscale image into a binary image to get the text
ret,imgBinText = cv2.threshold(imgGray,5,255,cv2.THRESH_BINARY)

# Changing white pixels from original image to black
img[imgBinAll == 255] = [0,0,0]

# Changing black pixels from original image to white
img[imgBinText == 0] = [255,255,255]

# Finishing time measurement
e2 = cv2.getTickCount()
t = (e2 - e1)/cv2.getTickFrequency()
print(f'Time spent in seconds: {t}')

At this point I stopped timing because the next step is just to plot the montage, the code follows:此时我停止计时,因为下一步只是绘制蒙太奇,代码如下:

# Plotting the image
plt.subplot(1,5,1),plt.imshow(original)
plt.title('original')
plt.xticks([]),plt.yticks([])
plt.subplot(1,5,2),plt.imshow(imgGray,'gray')
plt.title('grayscale')
plt.xticks([]),plt.yticks([])
plt.subplot(1,5,3),plt.imshow(imgBinAll,'gray')
plt.title('binary - all')
plt.xticks([]),plt.yticks([])
plt.subplot(1,5,4),plt.imshow(imgBinText,'gray')
plt.title('binary - text')
plt.xticks([]),plt.yticks([])
plt.subplot(1,5,5),plt.imshow(img,'gray')
plt.title('final result')
plt.xticks([]),plt.yticks([])
plt.show()

That is the final result:这是最终的结果:

Montage showing all steps of the proposed approach蒙太奇显示了所提议方法的所有步骤

And this is the time consumed (printed in the console):这是消耗的时间(打印在控制台中):

Time spent in seconds: 0.008526025

In order to compare both approaches I commented the line where the image is resized.为了比较这两种方法,我评论了调整图像大小的行。 Also, I stopped timing before the imshow command.另外,我在imshow命令之前停止了计时。 These were the results:结果如下:

Time spent in seconds: 1.837972522

Final result of the looping approach循环方法的最终结果

If you examine both images you'll see some contour differences.如果您检查两个图像,您会看到一些轮廓差异。 Sometimes when you are working with image processing, efficiency is key.有时,当您进行图像处理时,效率是关键。 Therefore, it is a good idea to save time where it is possible.因此,在可能的情况下节省时间是个好主意。 This approach can be adapted for different situations, take a look at the threshold documentation .这种方法可以适用于不同的情况,请查看阈值文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM