简单的图像处理

在这篇文章,将简要地分别通过MATLAB、Python、JavaScript来实现一些图像处理的基本操作

Python篇

获取图片的信息

图像的尺寸

import cv2
img = cv2.imread('test.jpg')
size = img.shape
print(size)
height,width,channels = img.shape
print(height,width,channels)

# 或者

from PIL import Image
img = Image.open('test.jpg')
imgSize = img.size
print(max(imgSize),min(imgSize))

图片缩放

samll_img = cv2.resize(src=img, dsize=None, fx=0.5, fy=0.5)
# 宽高缩小为原来的一半

复制图像

import cv2
import numpy as np

img = cv2.imread('test.jpg')
size = img.shape
im = np.zeros(img.shape, np.uint8)

# 也可以直接:
im = img.copy()

PIL图片和opencv图片相互转换

OpenCV to PIL:

pil = Image.fromarray(cv2.cvtColor(cv, cv2.COLORBGR2RGB))

PIL to OpenCV:

pil = PIL.Image.open('test.jpg').convert('RGB')
cv = numpy.array(pil)
cv = cv[:,:,::-1].copy()

灰度化

通过matplotlab库灰度化

首先安装matplotlab库:sudo pip install matplotlib

import matplotlib.pyplot as plt
import matlotlib.image as mpimg
import numpy as np
img = mpimg.imread('test.jpg')
img.shape 
# (282, 292, 3)
plt.axis('on') #显示坐标轴
plt.show()  #显示原图片

def rgb2gray(rgb):
    return np.dot(rgb[...,:3], [0.299, 0.587, 0.114])

gray = rgb2gray(img)
plt.imshow(gray,cmap = plt.get_cmap('gray'))
plt.axis('on')
plt.show()

通过PIL灰度化

from PIL import Image
img = Image.open('test.jpg')
img.show() # 显示原图
L = img.convert('L') # 灰度化
L.show() # 显示灰度图
L = img.convert('1') # 二值化
L.show() # 二值化图

扩展:将某路径下的所有彩色图片灰度化:

from PIL import Image
import os
def get_path(path):
	return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.jpg')]
pth = get_path('./')
print(pth)
for img in pth:
	outfile = os.path.splitext(img)[0] + '.jpg'
	print(outfile)
	if './gray'+outfile.split('./')[1] not in pth and 'gray' not in outfile:
	#if 'gray' not in outfile:
		#print('1'+img)
		try:
			img = Image.open(img).convert('L')
			#print('img',img)
			#img.show()
			im = 'gray' + outfile.split('./')[1]	
			img.save(im)
		except IOError:
			print('can not convert',img)

通过opencv灰度化

import cv2
from matpplotlib import pyplot as plt
im = cv2.imread('test.jpg')
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
plt.axis('off')
plt.imshow(im,'gray') # = plt.imshow(gray,cmap='gray') or plt.imshow(gray, cmap=plt.get_cmap('gray'))
plt.show()

在一些编程社区上经常看到:cv2.imshow(gray,'gray')这样的代码,但是查阅了Python opencv官网却没发现这样的格式。并且本人在调用opencv的时候调用了cv2.imshow('img',img),然后就出现了进程无反应的状况,目前原因不详

问题解决:针对上述不显示图片并且进程卡死的问题,给出下列的解决方案:

import cv2
im = cv2.imread('test1.jpg') # cv2.imread('test1.jpg',0)直接输出灰度图
gray = cv2.cvtColor(im,cv2.COLOR_RGB2GRAY) 
cv2.nameWindow('gray',0)
cv2.startWindowThread()
cv2.imshow('gray',gray)
cv2.waitKey(0)
cv2.destroyAllWindows()

bug解决请参考:cv2.destoryAllWindows()无效的解决方法

详情可以查看opencv官方文档:https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_gui/py_image_display/py_image_display.html

二值化

opencv

固定阈值二值化
用到的函数:cv2.threshold(src, thresh, maxval, type[, dst]),返回值为retval、dst

参数说明:

  • src:输入图像
  • thresh:阈值
  • maxval:输出图像最大值
  • type:阈值类型
  • dst:目标图像
retval, im = cv2.threshold(gray, 50, 255, cv2.THRESH_BINARY)
plt.axis('off')
plt.title('二值化')
plt.imshow()

算法平均法的自适应二值化和高斯加权均值自适应二值化
用到的函数:`cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst])`,返回值为`dst`

参数说明:

  • src:输入图像
  • maxval:输出图像的最大值
  • adaptiveMethod:设置为cv2.ADAPTIVE_THRESH_MEAN_C表示使用算术平均值法,设置为cv2.ADAPTIVE_THRESH_GAUSSIAN_C表示使用高斯权重均值法
  • thresholdType:阈值类型
  • blockSize:b的值
  • C:从均值中减去的常数,用于得到阈值
  • dst:目标图像

这里,我们将b设为5,C设为10

im = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,5,10)
plt.axis('off')
plt.title('Adaptive Thresholding')
plt.imshow(im, cmap='gray')
plt.show()

绘制直方图

通过matplotlib库绘制灰度直方图

灰度图可以使用hist函数绘制,这个函数第一个参数只能接受一位数组作为输入,所以第一个参数需要通过flatten将任意数组按照行优先准则转换为一维数组;第二个参数则是规定小区间的数目。

from PIL import Image
from pylab import *
# 图片转换为数组并灰度化
img = array(Image.open('test.jpg').convert('L'))
# 直方图图像
hist(img.flatten(),128)
show()

或者这样:

import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
im = np.array(Image.open('test.jpg').convert('L'))
plt.figure('gray')
plt.title('gray')
arr = im.flatten()
n,bins,patches = plt.hist(arr, bins=256, density=1, facecolor='blue', alpha=0.7)
plt.show()

hist的参数说明:

  • arr: 需要计算直方图的一维数组
  • bins:直方图柱数,可选,默认为10
  • density/normed:是否将得到的直方图向量归一化,默认为0
  • facecolor:直方图颜色
  • alpha:透明度

facecolor和edgecolor可以分别简写为fcec

更多函数说明参考官方库:https://matplotlib.org/api/_as_gen/matplotlib.pyplot.hist.html

如果需要显示彩色图的直方图:

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
im = Image.open('test.jpg')
r,g,b = im.split()
# 也可以r = im[:,:,0], g = im[::,1], b = im[:,:,2]
plt.figure('Origin')
plt.title('Origin')
arr = np.array(r).flatten()
plt.hist(arr, bins=256, density=1, facecolor='r', edgecolor='r', hold=1)
arr = np.array(g).flatten()
plt.hist(arr, bins=256, density=1, facecolor='g', edgecolor='g', hold=1)
arr = np.array(b).flatten()
plt.hist(arr, bins=256, density=1, facecolor='b', edgecolor='b', hold=1)
plt.show()

形态学

膨胀和腐蚀

和MATLAB一样,Python opencv的膨胀腐蚀函数分别是dilateerode

简单地先通过OTSU二值化再进行腐蚀膨胀:

#coding=utf-8

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

while(1):
	im = cv2.imread('zui.jpg',0)
	ret,th = cv2.threshold(im, 0, 255, cv2.THRESH_OTSU)
	#plt.imshow(th,'otsu')
	kernel = np.ones((3,3),np.uint8)
	im1 = cv2.erode(th,kernel,iterations=7)
	im2 = cv2.dilate(im1,kernel,iterations=1)
	cv2.imshow('dilation',im2)
	if cv2.waitKey(0):
		break
cv2.destroyAllWindows()

开运算和闭运算:

import cv2
import numpy as np
while(1):
    im = cv2.imread('test.jpg',0)
    kernel = np.ones((3,3),np.uint8)
    # or cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
    open = cv2.morphologyEx(im, cv2.MORPH_OPEN, kernel)
    # 如果是闭运算就是cv2.MORPH_CLOSE
    cv2.imshow('Gray',im)
    cv2.imshow('opening',open)
    if cv2.waitKey(0):
        break
cv2.destroyAllWindows()

更多有关Python opencv形态学的内容可以看:OpenCV-Python Tuorials Morphological Transformations

边沿检测:

#coding=utf-8

import cv2
import numpy as np

im = cv2.imread('zui.jpg')
im = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
dilation = cv2.dilate(im,kernel)
erodetion = cv2.erode(im, kernel)
edge = cv2.absdiff(dilation, erodetion) #两幅图相减得到边缘
ret,edge = cv2.threshold(edge, 50, 100, cv2.THRESH_BINARY) #二值化后观察更清晰
edge = cv2.bitwise_not(edge) #颜色反转
cv2.imshow('Origin',im)
cv2.imshow('Edge',edge)
if cv2.waitKey(0):
	cv2.destroyAllWindows()

角点检测:

基本原理:
建立一个窗口区域,该窗口向各个方向进行平移,如果在没有遇到边角的情况下,窗口像素不会发送变化;如果窗口在偏移过程压过一条直线,并且沿着这条直线的方向进行平移,窗口像素值也不会变化;假如遇到了拐角,窗口偏移后任意方向都会有像素改变,即判断为角点

基本方法:cv2.cornerHarris()cv2.cornerSubPix()
cornerHarris参数说明:

  • img:输入图像,数据类型要是float32
  • blockSize:角点检测中的邻域值
  • ksize:使用Sobel函数求偏导的窗口大小
  • k:角点检测参数,取值为0.04到0.06
import cv2
import numpy as np

filename = 'test.jpg'

im = cv2.imread(filename)
gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
gray = np.float32(gray)
dst = cv2.cornerHarris(gray, 2,3,0.04)
dst = cv2.dilate(dst,None) #膨胀处理
im[dst > 0.01*dst.max()] = [0,0,255]
cv2.imshow('dst',im)
if cv2.waitKey(0):
    cv2.destroyAllWindows()

亚像素级精确度的角点:
基本方法是cornerSubPix,首先需要先找到Harris角点,然后找到某个角点的所有角点坐标值的重心,传入cornerSubPix(因为一个角点上可能有一堆角点,所以要取重心)。我们用红色表示Harris角点,绿色表示修正后的角点。通过迭代运算到一定次数停止:

#coding=utf-8

import cv2
import numpy as np

filename = 'zui.jpg'
img = cv2.imread(filename)
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)

# 找角点
gray = np.float32(gray)
dst = cv2.cornerHarris(gray,2,3,0.04)
dst = cv2.dilate(dst,None)
ret,dst = cv2.threshold(dst,0.01*dst.max(),255,0)
dst = np.uint8(dst)

# 找重心
ret,labels,stats,centroids = cv2.connectedComponentsWithStats(dst)

# 定义迭代次数
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
corners = cv2.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria) # 返回角点

res = np.hstack((centroids,corners))
res = np.int0(res)
img[res[:,1],res[:,0]] = [0,0,255]
img[res[:,3],res[:,2]] = [0,255,0]

cv2.imshow('img',img)
if cv2.waitKey(0):
	cv2.destroyAllWindows()
#coding=utf-8
# 代码来自:https://zhuanlan.zhihu.com/p/36801693
import cv2
import numpy as np

# 读取名称为 p14.png的图片
img = cv2.imread("p14.png",1)
img_org = cv2.imread("p14.png",1)

# 转换为黑白图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 转换为32为浮点数
gray = np.float32(gray)

# Harris角点操作
processed = cv2.cornerHarris(gray,3,3,0.05)

# 把角点颜色变为绿色
img[processed>0.03*processed.max()] = [0,255,0]

# 显示原图和处理后的图像
cv2.imshow("org",img_org)
cv2.imshow("processed",img)

cv2.waitKey(0)




参考: