準備1:OpenCVの人気グラフィック変換技術
コンピュータビジョンモデルのトレーニングを行う前に、私たちはしばしば、より多くのサンプルを取得するために、画像強調技術を使用しますが、この方法は、いくつかの深学習フレームワークは、イメージが私たちのニーズを満たしていない可能性が道を変換するために、ので、いくつかの把握OpenCVの私たちのための一般的な画像処理技術は、まだ多くの援助を持っています。
チャンネルセパレーションの画像
私たちは、各画像は3色のRGBチャンネルで構成されていることを知っているので、私たちは、元の画像を分離するための3つのチャネル分割機能を使用することができます。
B、G、R = cv2.split(IMG)
チャネル分離が行われた後、我々は、各チャンネルの独立した値を変換することができ、そのような画像の明るさを高めるために新しいイメージ組成物を生成するための変換を完了すること。
B、G、R = cv2.split(IMG) のためにI(B、G、R): randint = random.randint(50,100) 限界= 255 randint I [I>リミット] = 255 iが[iが=限度を< ] = randint + I [iが=限界< img_merge = cv2.merge((B、G、R))を cv2.imshow( "img_merge"、img_merge) キー= cv2.waitKey() キー== 27であれば: CV2。 destroyAllWindows()
画像の回転
WarpAffine機能はまた私達の集合による画像の回転角度を完了するために使用することができます。
M = cv2.getRotationMatrix2D((img.shape [1] / 2、img.shape [0] / 2)、30、1) img_rotate = cv2.warpAffine(IMG、M、(img.shape [1]、IMG。 [0]))形状 cv2.imshow( 'img_rotate'、img_rotate) キー= cv2.waitKey(0) であれば、キー== 27: cv2.destroyAllWindows()
ここでは、画像の拡大縮小、30度の回転角度をしないでください。
アフィン変換
そして、画像アフィン変換傾斜伸縮を可能にする任意の二方向に起こり得ます。コードは以下の通りであります:
デフrandom_warp(IMG、行、列): 高さ、幅、チャネル= img.shape random_margin = 100 ×1 = random.randint(-random_margin、random_margin) Y1 = random.randint(-random_margin、random_margin) X2 = random.randint(幅- random_margin - 1、幅- 1) Y2 = random.randint(-random_margin、random_margin) X3 = random.randint(幅- random_margin - 1、幅- 1) Y3 = random.randint(高- random_margin - 1、高さ- 1) ×4 = random.randint(-random_margin、random_margin) Y4 = random.randint(高- random_margin - 1、高さ- 1) DX1 = random.randint(-random_margin、random_margin) DY1 = random.randint(-random_margin、 random_margin) DX2 = random.randint(幅- random_margin - 1、幅- 1) DY2 = random.randint(-random_margin、random_margin) DX3 = random.randint(幅- random_margin - 1、幅- 1) DY3 = random.randint(高- random_margin - 1、高さ- 1) DX4 = random.randint( - random_margin、random_margin) DY4 = random.randint(高- random_margin - 1、高さ- 1) PTS1 = np.float32([X1、Y1]、[X2、Y2]、[X3、Y3]、[X4、Y4] ]) PTS2 = np.float32([DX1、DY1]、[DX2、DY2]、[DX3、DY3]、[DX4、DY4]]) M_warp = cv2.getPerspectiveTransform(PTS1、PTS2) img_warp = cv2.warpPerspective( IMG、M_warp、(幅、高さ)) リターンimg_warp img_warp = random_warp(IMG、img.shape [0]、img.shape [1]) cv2.imshow( 'img_warp'、img_warp) キー= cv2.waitKey(0) もし、キー== 27: cv2.destroyAllWindows()
ガンマ補正
画像がより見えるようにガンマ補正は、画像のコントラストを向上させる「明るいです。」コードは以下の通りであります:
DEF adjust_gamma(画像、ガンマ= 1.0): invGamma = 1.0 /ガンマ テーブル= [] のIの範囲内(256): table.append(((I / 255.0)** invGamma)* 255) 表= np.array(表).astype( "UINT8") 戻りcv2.LUT(画像、テーブル) img_gamma = adjust_gamma(IMG、2) cv2.imshow( "IMG"、IMG) cv2.imshow( "img_gamma"、img_gamma) キー=のCV2。 waitKey() の場合、キー== 27: cv2.destroyAllWindows()
準備2:ダウンロードしてインストールCV2
次のようにホイールをダウンロード:
その後、直接ピップのコマンドを使用:
ピップopencv_python-3.4.3-CP37-cp37m-win_amd64.whlをインストール
注意:今、Python用のOpenCVはnumpyので拘束されています。そのため、使用はnumpyののいくつかの知識を習得しなければなりません!画像は、Python用のOpenCVで行列で、画像アレイnumpyの中です!
図1に示すように、画像のロード、記憶および表示
画像が読み込まれている場合、唯一の関数imreadをすることができます。
CV2インポート #ピクチャーゲット img_path = r'1.jpg「 IMG = cv2.imread(img_path)
OpenCVのは、現在読んBMP、JPG、PNG、TIFFおよびその他の一般的なフォーマットをサポートしています。
また、画像の基本的な属性のいくつかを見ることができます:
印刷(IMG) プリント(img.dtype) プリント(img.shape)
その後、ウィンドウを作成
cv2.namedWindow( "イメージ")
画像は、ウィンドウ内に表示されます
cv2.imshow( 'イメージ'、IMG)
最後に、文を追加します。
cv2.waitKey(0)
あなたは、IDLE直接的な応答で、実行ウィンドウを最後の文を追加しない場合。次に、コマンドラインを実行し、それはつかの間です。
画像を保存非常に簡単で、直接cv.imwrite缶。
cv2.imwrite(save_path、crop_img)
最初のパラメータは、第二の画像行列で、保存するパスとファイル名です。以下の通りであり、関数imwrite()は、任意の第三のパラメータがあります。
cv2.imwrite( "はcat.jpg"、IMG、[INT(cv2.IMWRITE_JPEG_QUALITY)、5])
特定のフォーマットのための第三のパラメータ:JPEGの場合、画像の品質を表す0から100の整数で表され、デフォルト値は95です。注、ロングcv2.IMWRITE_JPEG_QUALITYタイプ、intに変換する必要があります。次の2つの図は、異なる品質に格納されています。
PNG、第3のパラメータは、圧縮のレベルを示します。画像のサイズ0から9までcv2.IMWRITE_PNG_COMPRESSION、圧縮のレベルが高いほど、小さいです。デフォルトのレベルは3です。
cv2.imwrite( "./ cat.png"、IMG、[INT(cv2.IMWRITE_PNG_COMPRESSION)、0]) cv2.imwrite( "./ cat2.png"、IMG、[INT(cv2.IMWRITE_PNG_COMPRESSION)、9])
次のように画像サイズを保存:
画像のサポートもあり、一般的に使用されていません。
完全なプログラムは以下のとおりです。
ます。#/ usr / bin / envをパイソン! # - * -コーディング:UTF-8 - * - インポートCV2 #获取图片 img_path = r'1.jpg」 IMG = cv2.imread(img_path) cv2.namedWindow( "イメージ") cv2.imshow( 'イメージ'、IMG) cv2.waitKey(0) cv2.destroyAllWindows()
最後のリリースウィンドウは良い習慣です!次のように画像の効果がある見ます:
2、及びグレースケールノイズを変換します
我々は、二つの絵を得ることができます最初はグレースケール画像である、第二章では、ノイズ除去の後です。多くの方法は、ノイズ除去は平均フィルタリング、ガウシアンフィルタ、メディアンフィルタ、バイラテラルフィルタなどがあります。ここで階調表示、ガウス雑音除去コード:
灰色= cv2.cvtColor(IMG、cv2.COLOR_BGR2GRAY)は (9)、0、グレー、(9)= cv2.GaussianBlurをぼやけ
下图展示效果,(这里取高斯是因为高斯去噪效果是最好的)
3,提取图像的梯度
用Sobel算子计算x,y方向上的梯度,之后在x方向上 minus y方向上的梯度,通过这个操作,会留下具有高水平梯度和低垂直梯度的图像区域。
代码入下:
# 提取图像的梯度 gradX = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=1, dy=0) gradY = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=0, dy=1) gradient = cv2.subtract(gradX, gradY) gradient = cv2.convertScaleAbs(gradient)
此时我们会得到如下的图像:
4,继续去噪声
考虑到图像的孔隙,首先使用低通滤波器平滑图像,这将有助于平滑图像中的高频噪声。低通滤波器的目的是降低图像的变化率。
如果将每个像素替换为该图像周围像素的均值,这样就可以平滑并替代那些强度变化明显的区域。
对模糊图像二值化,顾名思义就是把图像数值以某一边界分成两种数值:
blurred = cv2.GaussianBlur(gradient, (9, 9), 0) (_, thresh) = cv2.threshold(blurred, 90, 255, cv2.THRESH_BINARY)
此时效果如下:
其实就算手动分割,我们也是需要找到一个边界,可以看出轮廓出来了,但是我们最终要的是整个轮廓,所以内部小区域就不要了。
5,图像形态学
在这里我们选取ELLIPSE核,采用CLOSE操作。
# 图像形态学 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (25, 25)) closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
此时,效果如下:
6,细节刻画
从上图我们可以发现和原图对比,发现有细节丢失,这会干扰之后的昆虫轮廓的检测,要把它们扩充,分别执行4次形态学腐蚀与膨胀,代码如下:
# 细节刻画,分别执行四次形态学腐蚀与膨胀 closed = cv2.erode(closed, None, iterations=4) closed = cv2.dilate(closed, None, iterations=4)
效果如下:
7,找出昆虫区域的轮廓,并画出
此时用 cv2.findContours() 函数如下:
(_, cnts, _) = cv2.findContours( 参数一: 二值化图像 closed.copy(), 参数二:轮廓类型 #表示只检测外轮廓 # cv2.RETR_EXTERNAL, #建立两个等级的轮廓,上一层是边界 # cv2.RETR_CCOMP, #检测的轮廓不建立等级关系 # cv2.RETR_LIST, #建立一个等级树结构的轮廓 # cv2.RETR_TREE, #存储所有的轮廓点,相邻的两个点的像素位置差不超过1 # cv2.CHAIN_APPROX_NONE, 参数三:处理近似方法 #例如一个矩形轮廓只需4个点来保存轮廓信息 # cv2.CHAIN_APPROX_SIMPLE, # cv2.CHAIN_APPROX_TC89_L1, # cv2.CHAIN_APPROX_TC89_KCOS )
第一个参数是要检索的图片,必须是二值图,即黑白的(不是灰度图)。
# 这里opencv3返回的是三个参数 (_, cnts, _) = cv2.findContours( # 参数一:二值化图像 closed.copy(), # 参数二:轮廓类型 cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE ) c = sorted(cnts, key=cv2.contourArea, reverse=True)[0] rect = cv2.minAreaRect(c) box = np.int0(cv2.boxPoints(rect)) draw_img = cv2.drawContours(img.copy(), [box], -1, (0, 0, 255), 3) cv2.imshow("draw_img", draw_img)
此时,会得到:
8,裁剪
图像的裁剪最简单的方式就是获取图像数组的切片,如下:
img_crop = img[100:300,100:300] cv2.imshow("img_crop", img_crop) key = cv2.waitKey() if key == 27: cv2.destroyAllWindows()
当然,这里我们直接找到四个点,切出来就OK.
其实,box里保存的是绿色矩阵区域四个顶点的坐标。我们按照下图所示裁剪昆虫图像。
方法是找到四个顶点的x,y坐标的最大最小值。新图像的高等于 max(Y) - min(Y),宽等于 max(X) - min(X)。
Xs = [i[0] for i in box] Ys = [i[1] for i in box] x1 = min(Xs) x2 = max(Xs) y1 = min(Ys) y2 = max(Ys) hight = y2 - y1 width = x2 - x1 crop_img= img[y1:y1+hight, x1:x1+width] cv2.imshow('crop_img', crop_img)
9,完整代码
#-*- coding: UTF-8 -*- import cv2 import numpy as np def get_image(path): #获取图片 img=cv2.imread(path) gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) return img, gray def Gaussian_Blur(gray): # 高斯去噪 blurred = cv2.GaussianBlur(gray, (9, 9),0) return blurred def Sobel_gradient(blurred): # 索比尔算子来计算x、y方向梯度 gradX = cv2.Sobel(blurred, ddepth=cv2.CV_32F, dx=1, dy=0) gradY = cv2.Sobel(blurred, ddepth=cv2.CV_32F, dx=0, dy=1) gradient = cv2.subtract(gradX, gradY) gradient = cv2.convertScaleAbs(gradient) return gradX, gradY, gradient def Thresh_and_blur(gradient): blurred = cv2.GaussianBlur(gradient, (9, 9),0) (_, thresh) = cv2.threshold(blurred, 90, 255, cv2.THRESH_BINARY) return thresh def image_morphology(thresh): # 建立一个椭圆核函数 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (25, 25)) # 执行图像形态学, 细节直接查文档,很简单 closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) closed = cv2.erode(closed, None, iterations=4) closed = cv2.dilate(closed, None, iterations=4) return closed def findcnts_and_box_point(closed): # 这里opencv3返回的是三个参数 (_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) c = sorted(cnts, key=cv2.contourArea, reverse=True)[0] # compute the rotated bounding box of the largest contour rect = cv2.minAreaRect(c) box = np.int0(cv2.boxPoints(rect)) return box def drawcnts_and_cut(original_img, box): # 因为这个函数有极强的破坏性,所有需要在img.copy()上画 # draw a bounding box arounded the detected barcode and display the image draw_img = cv2.drawContours(original_img.copy(), [box], -1, (0, 0, 255), 3) Xs = [i[0] for i in box] Ys = [i[1] for i in box] x1 = min(Xs) x2 = max(Xs) y1 = min(Ys) y2 = max(Ys) hight = y2 - y1 width = x2 - x1 crop_img = original_img[y1:y1+hight, x1:x1+width] return draw_img, crop_img def walk(): img_path = r'C:\Users\aixin\Desktop\chongzi.png' save_path = r'C:\Users\aixin\Desktop\chongzi_save.png' original_img, gray = get_image(img_path) blurred = Gaussian_Blur(gray) gradX, gradY, gradient = Sobel_gradient(blurred) thresh = Thresh_and_blur(gradient) closed = image_morphology(thresh) box = findcnts_and_box_point(closed) draw_img, crop_img = drawcnts_and_cut(original_img,box) # 暴力一点,把它们都显示出来看看 cv2.imshow('original_img', original_img) cv2.imshow('blurred', blurred) cv2.imshow('gradX', gradX) cv2.imshow('gradY', gradY) cv2.imshow('final', gradient) cv2.imshow('thresh', thresh) cv2.imshow('closed', closed) cv2.imshow('draw_img', draw_img) cv2.imshow('crop_img', crop_img) cv2.waitKey(20171219) cv2.imwrite(save_path, crop_img) walk()
附录代码:
# 用来转化图像格式的 img = cv2.cvtColor(src, COLOR_BGR2HSV # BGR---->HSV COLOR_HSV2BGR # HSV---->BGR ...) # For HSV, Hue range is [0,179], Saturation range is [0,255] and Value range is [0,255] # 返回一个阈值,和二值化图像,第一个阈值是用来otsu方法时候用的 # 不过现在不用了,因为可以通过mahotas直接实现 T = ret = mahotas.threshold(blurred) ret, thresh_img = cv2.threshold(src, # 一般是灰度图像 num1, # 图像阈值 num2, # 如果大于或者num1, 像素值将会变成 num2 # 最后一个二值化参数 cv2.THRESH_BINARY # 将大于阈值的灰度值设为最大灰度值,小于阈值的值设为0 cv2.THRESH_BINARY_INV # 将大于阈值的灰度值设为0,大于阈值的值设为最大灰度值 cv2.THRESH_TRUNC # 将大于阈值的灰度值设为阈值,小于阈值的值保持不变 cv2.THRESH_TOZERO # 将小于阈值的灰度值设为0,大于阈值的值保持不变 cv2.THRESH_TOZERO_INV # 将大于阈值的灰度值设为0,小于阈值的值保持不变 ) thresh = cv2.AdaptiveThreshold(src, dst, maxValue, # adaptive_method ADAPTIVE_THRESH_MEAN_C, ADAPTIVE_THRESH_GAUSSIAN_C, # thresholdType THRESH_BINARY, THRESH_BINARY_INV, blockSize=3, param1=5 ) # 一般是在黑色背景中找白色物体,所以原始图像背景最好是黑色 # 在执行找边缘的时候,一般是threshold 或者是canny 边缘检测后进行的。 # warning:此函数会修改原始图像、 # 返回:坐标位置(x,y), (_, cnts, _) = cv2.findContours(mask.copy(), # cv2.RETR_EXTERNAL, #表示只检测外轮廓 # cv2.RETR_CCOMP, #建立两个等级的轮廓,上一层是边界 cv2.RETR_LIST, #检测的轮廓不建立等级关系 # cv2.RETR_TREE, #建立一个等级树结构的轮廓 # cv2.CHAIN_APPROX_NONE, #存储所有的轮廓点,相邻的两个点的像素位置差不超过1 cv2.CHAIN_APPROX_SIMPLE, #例如一个矩形轮廓只需4个点来保存轮廓信息 # cv2.CHAIN_APPROX_TC89_L1, # cv2.CHAIN_APPROX_TC89_KCOS ) img = cv2.drawContours(src, cnts, whichToDraw(-1), color, line) img = cv2.imwrite(filename, dst, # 文件路径,和目标图像文件矩阵 # 对于JPEG,其表示的是图像的质量,用0-100的整数表示,默认为95 # 注意,cv2.IMWRITE_JPEG_QUALITY类型为Long,必须转换成int [int(cv2.IMWRITE_JPEG_QUALITY), 5] [int(cv2.IMWRITE_JPEG_QUALITY), 95] # 从0到9,压缩级别越高,图像尺寸越小。默认级别为3 [int(cv2.IMWRITE_PNG_COMPRESSION), 5]) [int(cv2.IMWRITE_PNG_COMPRESSION), 9]) # 如果你不知道用哪个flags,毕竟太多了哪能全记住,直接找找。 寻找某个函数或者变量 events = [i for i in dir(cv2) if 'PNG' in i] print( events ) 寻找某个变量开头的flags flags = [i for i in dir(cv2) if i.startswith('COLOR_')] print flags 批量读取文件名字 import os filename_rgb = r'C:\Users\aixin\Desktop\all_my_learning\colony\20170629' for filename in os.listdir(filename_rgb): #listdir的参数是文件夹的路径 print (filename)
参考文献: