SciTech-BigDataAI-ImageProcessing-Numerical Analysis-Useful Operations-Color Image Channels with OpenCV+NumPy+Pandas
Links:
- https://pyimagesearch.com/2021/01/23/splitting-and-merging-channels-with-opencv/
- OpenCV Official:
https://docs.opencv.org/3.4/d3/df2/tutorial_py_basic_ops.html - Background Subtraction Tutorial:
https://docs.opencv.org/3.4/d1/dc5/tutorial_background_subtraction.html - OpenCV Examples:
https://docs.opencv.org/3.4/d5/de8/samples_2cpp_2segment_objects_8cpp-example.html - 多看open CV的"示例代码"和"官方文档"
Shortpath Codes
Remove Background Color
# Usage: ipython --pdb removeColor.py 18
#! /usr/bin/env python
import itertools as it
import collections as ct
import cv2 as cv
import numpy as np
import pandas as pd
def calculate_top_color(image):
a = image.copy()
cnt = ct.Counter(a)
topTen = cnt.most_common(10)
topTenColors=[k for k,v in topTen]
topColor=np.array(topTenColors).mean()
return topColor
def replace_color(image, top=None, threshold=5, color=255):
color_threshold = threshold
a = image.copy()
s = pd.Series(image.flatten())
rows, cols = image.shape
topColor0 = top or calculate_top_color(s)
topColor = top or int(s.describe()['50%'])
colorMin = topColor - color_threshold
colorMax = topColor + color_threshold
print(s.describe(), '\n', "TopColor: %s, %s\n" % (topColor, topColor0))
for r in range(rows):
for c in range(cols):
val = a.item(r, c)
if colorMin <= val < colorMax:
a.itemset((r, c), color)
return a
def remove_top_color(img, top=None, threshold=18, color=255):
b, g, r =img[:, :, 0], img[:, :, 1], img[:, :, 2]
print("\nProcessing Color Channel: BLUE")
b = replace_color(b, top, threshold, color)
print("\nProcessing Color Channel: GREEN")
g = replace_color(g, top, threshold, color)
print("\nProcessing Color Channel: RED")
r = replace_color(r, top, threshold, color)
img0 = cv.merge((b, g, r))
return img0
if __name__ == "__main__":
import os,sys
threshold = int(sys.argv[1]) if len(sys.argv) > 1 else 18
# Load the image first
img_path = './Signature.jpg'
img0 = cv.imread(img_path)
assert img0 is not None, "file could not be read, check with os.path.exists('%s')" % img_path
cv.imwrite('Original.jpg', img0)
img1 = remove_top_color(img0, threshold=threshold)
cv.imwrite('Output.jpg', img1)
import itertools as it
import collections as ct
import cv2 as cv
import numpy as np
import pandas as pd
# Load the image first
img_path = './Signature.jpg'
img = cv.imread(img_path)
assert img is not None, "file could not be read, check with os.path.exists('%s')" % img_path
# Color Channels Splitting and merging
b, g, r =img[:, :, 0], img[:, :, 1], img[:, :, 2] # faster than cv.split(img)
a = b.flatten()
# Save the original image
img0 = cv.merge((b, g, r))
cv.imwrite('Original.jpg', img0)
# Using Python's collections.Counter()
import collections as ct
topTen = ct.Counter(a).most_common(10)
# Using Pandas for Number Analysis and Statistics
ss, df = pd.Series(a), pd.DataFrame(b)
# Pandas Descriptive statistics Summarizing data: describe
ss.describe()
# Pandas: **select specific percentiles**:
# By default, the median is always included
percentiles = [0.05, 0.25, 0.75, 0.95]
ss.describe(percentiles=percentiles)
# Graystyle
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# bgSubtractor for background removal
bgSuber = cv.bgsegm.createBackgroundSubtractorMOG()
bgSuber.apply(img)
bgSuber_img = bgSuber.apply(img)
cv.imwrite('bgSuber.jpg', bgSuber_img)
# Perform morphology operation
morph_kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))
mask = cv.morphologyEx(bgSuber_img, cv.MORPH_CLOSE, morph_kernel)
res = cv.bitwise_and(img, img, mask=mask)
cv.imwrite('Result.jpg', res)
Accessing Image Properties
- Image properties include "number of rows, columns, and channels"; "type of image data"; "number of pixels"; etc.
- Note:
- it is a good method to check whether the loaded image is grayscale or color.
img.dtype
is very important while debugging,
because a large number of errors in OpenCV-Python code are caused by invalid datatype.
#1. **Total number of pixels** is accessed by `img.size`:
#2. **Image datatype** is obtained by `img.dtype`:
#3. **shape of an image** is accessed by `img.shape`, It returns
# a tuple of the number of rows, columns, and channels(if the image is color)
# a tuple of the number of rows and columns ONLY**if an image is grayscale**.
# **check whether the loaded image is grayscale or color** first by Using `3 == len(img.shape)` .
print( img.shape, img.size, img.dtype)
(342, 548, 3) 562248 uint8
Splitting and Merging Image Channels
Sometimes you will need to work separately on the B,G,R channels of an image.
- In this case, you need to split the BGR image into single channels.
- In other cases, you may need to join these individual channels to create a BGR image.
- Warning:
cv.split()
is a time costly operation. So use it only if necessary.
Otherwise go for Numpy indexing.
You can do this simply by:
b, g, r = cv.split(img)
img = cv.merge((b, g, r))
# OR a better faster way by using **Numpy indexing**
b, g, r =img[:,:,0], img[:,:,0] img[:,:,0]
img = cv.merge((b, g, r))
# Suppose you want to set all the red pixels to zero
# **Numpy indexing is faster**,
# so you do not need to split the channels first.:
img[:,:,2] = 0
Accessing and Modifying pixel values
You can access a pixel value by its row and column coordinates.
- For BGR image, it returns an array of Blue, Green, Red values.
- For grayscale image, just corresponding intensity is returned.
# Access a pixel value by its row and column coordinates
px = img[100, 100]
print( px )
[157 166 200] # an array of Blue, Green, Red values for BGR image
# accessing only blue pixel
blue = img[100, 100, 0]
print( blue )
157
#You can modify the pixel values the same way.
img[100, 100] = [255, 255, 255]
print( img[100, 100] )
[255 255 255]
# **Better pixel accessing and editing method** :
# accessing only RED value
img.item(10, 10, 2)
59
# modifying RED value
img.itemset((10, 10, 2), 100)
img.item(10, 10, 2)
100
- Warning: Numpy is an optimized library for fast array calculations.
So simply accessing each and every pixel value and modifying it will be very slow and it is discouraged. - Note
- The above coordinates method is normally used for selecting a region of an array,
say the first 5 rows and last 3 columns. - For individual pixel access, the Numpy array methods, array.item() and array.itemset() are considered better.
They always return a scalar, however, so if you want to access all the B,G,R values, you will need to call array.item() separately for each value.
- The above coordinates method is normally used for selecting a region of an array,
ROI of Image
Sometimes, you will have to play with certain regions of images. For eye detection in images:
- first face detection is done over the entire image.
- when a face is obtained, we select the face region alone and search for eyes inside it instead of searching the whole image. It improves:
- accuracy, because eyes are always on faces 😄,
- performance, because we search in a small area.
ROI is again obtained using Numpy indexing.
# Here I am selecting the ball and copying it to another region in the image:
ball = img[280:340, 330:390]
img[273:333, 100:160] = ball
Check the results below
Making Borders for Images (Padding)
If you want to create a border around an image, something like a photo frame,
you can use cv.copyMakeBorder(). But it has more applications for convolution operation, zero padding etc. This function takes following arguments:
- src - input image
- top, bottom, left, right - border width in number of pixels in corresponding directions
- borderType - Flag defining what kind of border to be added. It can be following types:
- cv.BORDER_CONSTANT - Adds a constant colored border. The value should be given as next argument.
- cv.BORDER_REFLECT - Border will be mirror reflection of the border elements, like this : fedcba|abcdefgh|hgfedcb
- cv.BORDER_REFLECT_101 or cv.BORDER_DEFAULT - Same as above, but with a slight change, like this : gfedcb|abcdefgh|gfedcba
- cv.BORDER_REPLICATE - Last element is replicated throughout, like this: aaaaaa|abcdefgh|hhhhhhh
- cv.BORDER_WRAP - Can't explain, it will look like this : cdefgh|abcdefgh|abcdefg
- value - Color of border if border type is cv.BORDER_CONSTANT
Below is a sample code demonstrating all these border types for better understanding:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255, 0, 0]
img1 = cv.imread('opencv-logo.png')
assert img1 is not None, "file could not be read, check with os.path.exists()"
replicate = cv.copyMakeBorder(img1, 10,10,10,10, cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1, 10,10,10,10, cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1, 10,10,10,10, cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1, 10,10,10,10, cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1, 10,10,10,10, cv.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
See the result below. (Image is displayed with matplotlib. So RED and BLUE channels will be interchanged):
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理