image -processing-python-opencv

تقسیم و ادغام کانال های تصویری با opencv

۱- دسترسی به مقادیر پیکسل و تغییر آنها
۱-۲- img.shape
۱-۳- img.size
۱-۴- img.dtype
۲- Image ROI
۲-۱- تقسیم و ادغام کانال های تصویری با opencv
۲-۲- ساخت مرز و حاشیه برای تصاویر
۳- تبدیل هندسی تصاویر
۳-۱- Translation 
۳-۲- Rotation
۳-۳- Affine Transformation


تقریبا تمام عملیات در این بخش به طور عمده به Numpy بیشتر از  OpenCV مربوط می شود. دانش خوبی از Numpy برای نوشتن کد بهینه سازی بهتر با OpenCV لازم است.
* (نمونه ها در ترمینال پایتون نشان داده می شوند، زیرا اکثر آنها فقط کدهای خطی هستند)

 

دسترسی و تغییر مقادیر پیکسل – opencv

اجازه دهید یک تصویر رنگی را بار اول بگذاریم:

import cv2
import numpy as np
img = cv2.imread('img2.png')

شما می توانید از طریق مختصات ردیف و  ستون به یک مقدار پیکسل دسترسی پیدا کنید. برای تصویر BGR، آرایه ای از مقادیر آبی، سبز، قرمز را باز می گرداند. برای تصویر خاکستری ، فقط شدت  نور  متناظر بازگشته است.

px = img[100,100]
  print (px)
 [۲۴۷ ۲۵۳ ۲۳۴]
 blue = img[100,100,0]
 print (blue)
 ۲۴۷
  green = img[100,100,1]
  print(green)
 ۲۵۳
 red = img[100,100,2]
  print(red)
 ۲۳۴

شما می توانید مقادیر پیکسل را به همین شیوه تغییر دهید. به عنوان مثال :


 img[20,20] = [0,0,0]
 print (img[20,20])
 [۰ ۰ ۰]
point

تغییر مقدار پیکسل

 

هشدار

Numpy یک کتابخانه بهینه سازی شده برای محاسبات سریع آرایه است.
به سادگی دسترسی به هر یک از مقادیر پیکسل انجام میشود و اصلاح آن بسیار کند است و دلسرد کننده است.

نکته

روش فوق به طور معمول برای انتخاب یک قسمت  از آرایه استفاده می شود،مثلا میگویند: ۵ ردیف اول و ۳ ستون آخر آن .

برای دسترسی به پیکسل های تکی، متدهای  آرایهNumpy ،  () و array.itemset () array.item   بهتر است در نظر گرفته شود. اما همیشه یک اسکالر را برمیگرداند. بنابراین اگر میخواهید به تمام مقادیر B، G، R  دسترسی داشته باشید، باید با استفاده از array.item () به طور جداگانه برای همه صدا بزنید.

روش دسترسی و ویرایش بهتر پیکسل:

 img.item(20,20,2)
 ۰
 img.item(10,10,2)
 ۲۳۵
 img.itemset((20,20,2),100)
 img.item(20,20,2)
 ۱۰۰

img.shape

خواص تصویر شامل تعداد ردیف ها، ستون ها و کانال ها، نوع داده های تصویر، تعداد پیکسل ها و … است.

ویژگی های هر تصویر، توسط img.shape قابل دسترسی است. که شامل تعدادی از ردیف ها، ستون ها و کانال ها (اگر رنگ باشد)، است:

 print (img.shape)
 (۶۴۰, ۶۴۰, ۳)

توجه داشته باشید،اگر تصویر سیاه و سفید است، ویژگیۀ فقط تعداد ردیف ها و ستون ها را شامل می شود. بنابراین یک روش خوب برای بررسی اینکه آیا تصویر لود شده رنگ سیاه یا سفید است یا خیر.

img.size

 

تعداد کل پیکسل ها توسط img.size قابل دسترسی است:

 print (img.size)
 ۱۲۲۸۸۰۰

 

img.dtype

نوع داده تصویر توسط img.dtype بدست می آید:

 print (img.dtype)
 uint8

نکته

توجه داشته باشید img.dtype بسیار مهم است در اشکال زدایی، زیرا تعداد زیادی از خطاها در کد های  OpenCV-Python، ناشی از نوع داده معتبر است.

 

Image ROI

Region of Interest، همان طور که از نام آن مشخص است، یعنی منطقه ای از تصویر که توسط ما انتخاب می شود. دلیل این کار، این است که ما به جای انتخاب کل تصویر، فقط ناحیه ای که لازم است را مورد پردازش قرار می دهیم که باعث افزایش کارایی و سرعت در پرازش می شود. غیر مثال زیر نمونه بارز استفاده از این عملیات، تشخیص پلاک خودرو است.

گاهی اوقات، باید با یک منطقه خاص از تصاویر بازی کنید.
برای تشخیص چشم در تصاویر، اول تشخیص چهره در سراسر تصویر انجام می شود و هنگامی که چهره به دست آمد، ما تنها یک منطقه چهره را انتخاب می کنیم و به دنبال آن، چشم ها را در داخل آن تصویر، جستجو می کنیم. roi ، دقت را بهبود (چون چشمان همیشه روی چهره ها هستند) و عملکرد (به دلیل اینکه ما برای یک منطقه کوچک جستجو می کنیم) را افزایش میدهد.

در اینجا من با انتخاب الله در تصویر و کپی کردن،  آن را به یک منطقه دیگر در تصویر منتقل کردم:

import cv2
import numpy as np
img = cv2.imread('img2.PNG')
allah = img[105:190,435:521]
img[79:164,1:87] = allah
img[544:623,115:194] = [0,255,0]
img[544:623,17:96] = [255,0,0]
img[544:623,212:290] = [0,0,255]
cv2.namedWindow('My Image', cv2.WINDOW_NORMAL)
cv2.imshow('My Image',img)
cv2.waitKey(0)
Image ROI

Image ROI

 

تقسیم و ادغام کانال های تصویری  با opencv

گاهی اوقات شما باید جداگانه در کانال های B، G، R کار کنید. سپس شما نیاز دارید برای تقسیم تصاویر BGR به یک تک کاناله:

b,g,r = cv2.split(img)
blue =cv2.split(img)[0]
green=cv2.split(img)[1]
red = cv2.split(img)[2]
import cv2
import numpy
import matplotlib.pyplot
image = cv2.imread("img2.png",1)
print(image.shape)
b,g,r = cv2.split(image) # the order is not r,g,b
cv2.namedWindow("Image", cv2.WINDOW_NORMAL)
cv2.imshow("Image",image)
cv2.namedWindow("ImageR", cv2.WINDOW_NORMAL)
cv2.imshow("ImageR",r)
cv2.namedWindow("ImageG", cv2.WINDOW_NORMAL)
cv2.imshow("ImageG",g)
cv2.namedWindow("ImageB", cv2.WINDOW_NORMAL)
cv2.imshow("ImageB",b)
cv2.waitKey(0)
cv2.destroyAllWindows()
Region of Interes

Region of Interes

یا بعضی وقتها، ممکن است نیاز به پیوستن این کانال های فردی و تبدیل آن به  تصویر BGR باشید:

img = cv2.merge((b,g,r))
یا
b = img[:,:,0]

فرض کنید شما می خواهید تمام پیکسل های قرمز را صفر کنید
شما نیازی به تقسیم کردن این کار ندارید و آن را برابر صفر قرار دهید. شما می توانید به راحتی از Indexing Numpy استفاده کنید و سریع تر است.

img[:,:,2] = 0

شما می توانید تبدیل رنگ قرمز به سیاه را  به سادگی انجام دهید:

 

import cv2
import numpy as np
img = cv2.imread('img2.PNG')
b,g,r = cv2.split(img)
img = cv2.merge((b,g,r))
b = img[:,:,0]
img[:,:,2] = 0
cv2.namedWindow('My Image', cv2.WINDOW_NORMAL)
cv2.imshow('My Image',img)
cv2.waitKey(0)
Region of Interes

Region of Interes

 

 

هشدار

cv2.split () یک است  عملیات پر هزینه  (از لحاظ زمان) پس فقط اگر شما به آن نیاز دارید. در غیر اینصورت برای شاخص کردن Numpy بروید

 

ساخت مرز و حاشیه برای تصاویر

اگر می خواهید حاشیه ای در اطراف تصویر ایجاد کنید، چیزی شبیه یک قاب عکس، شما می توانید از تابع ()cv2.copyMakeBorder  استفاده کنید. اما این تابع کاربردهای بیشتری برای عملیات کانولوشن، صفر کردن و غیره دارد. این تابع با استفاده از آرگومانهای های زیر عمل می کند:
src – تصویر ورودی

top, bottom, left, right:  تعداد پیکسل ها در جهت های مربوطه

borderType: – پرچم  برای تعریف اینکه چه نوع حاشیه ای اضافه می شود. می تواند انواع زیر باشد:

cv2.BORDER_CONSTANT : حاشیه رنگ ثابت را اضافه می کند. ارزش باید به عنوان آرگومان بعدی داده شود.

cv2.BORDER_REFLECT : مرز بازتابی از عناصر مرزی است، مثل این: fedcba | abcdefgh | hgfedcb

cv2.BORDER_REFLECT_101 یا cv2.BORDER_DEFAULT – همانند بالا، اما با تغییر جزئی، مانند این است: gfedcb | abcdefgh | gfedcbacv2.BORDER_REPLICATE

cv2.BORDER_REPLICATE – آخرین عنصر در سراسر تکرار شده است، مانند این: aaaaaa | abcdefgh | hhhhhhh

cv2.BORDER_WRAP – نمی توان توضیح داد، به نظر می رسد: cdefgh | abcdefgh | abcdefg
value – رنگ مرزی اگر نوع مرزی cv2.BORDER_CONSTANT باشد
در زیر یک کد نمونه برای نشان دادن تمام این انواع مرز برای درک بهتر است:

قطعه کد زیر از  from matplotlib import pyplot as plt  برای نمایش استفاده کرده است.

 

import cv2
import numpy as np
from matplotlib import pyplot as plt
yellow = [255,255,0]
img1 = cv2.imread('openCV (1).png')
img2 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
replicate = cv2.copyMakeBorder(img2,10,10,10,10,cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img2,10,10,10,10,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img2,10,10,10,10,cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img2,10,10,10,10,cv2.BORDER_WRAP)
constant= cv2.copyMakeBorder(img2,10,10,10,10,cv2.BORDER_CONSTANT,value=yellow)
plt.subplot(231),plt.imshow(img2,'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()
copy-Make-Border

ساخت مرز و حاشیه برای تصاویر

در قطعه کد زیر از opencv برای نمایش استفاده شده است:

 

import cv2
import numpy
image = cv2.imread("openCV.png")
BLUE = [255,0,0]
replicate = cv2.copyMakeBorder(image,10,10,10,10,cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(image,10,10,10,10,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(image,10,10,10,10,cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(image,10,10,10,10,cv2.BORDER_WRAP)
constant= cv2.copyMakeBorder(image,10,10,10,10,cv2.BORDER_CONSTANT,value=BLUE)
#cv2.imshow("image",replicate)
#cv2.imshow("image",reflect)
cv2.namedWindow('My Image', cv2.WINDOW_NORMAL)
cv2.imshow("My Image",reflect101)
#cv2.imshow("image",wrap)
#cv2.imshow("image",constant)
#cv2.imshow("image",image)
cv2.waitKey(0)

 

در قطعه کد زیر نوشتن یک متن، رسم چند ضلعی، دایره ، مستطیل و یک خط نمایش داده شده است:

import numpy as np
import cv2
img = cv2.imread('carr.jpg',cv2.IMREAD_COLOR)
print(img.shape)
cv2.line(img,(0,0),(100,100),(255,255,255),5)
cv2.rectangle(img,(0,100),(100,200),(0,0,0),5)
cv2.circle(img,(63,250), 63, (0,255,0), -1)
pts = np.array([[10,100],[40,50],[50,10],[30,10]], np.int32)
pts = pts.reshape((-1,1,2))
cv2.polylines(img, [pts], True, (255,100,0), 3)
font = cv2.FONT_HERSHEY_SIMPLEX
# def putText(img, text, org, fontFace, fontScale, color, thickness=None, lineType=None, bottomLeftOrigin=None):<br data-jekyll-commonmark-ghpages="" />cv2.putText(img,"I Iove Lamborghini!",(200,40), 0, 0.8, (255,100,0), 3, cv2.LINE_AA)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
ساخت مرز و حاشیه برای تصاویر

ساخت مرز و حاشیه برای تصاویر

 

در این قطعه کد: تعداد کانال نوع تصویر با استفاده از if( در تصاویر رنگی img.shape  دارای ۳ مقدار طول، عرض و تعداد کانال میباشد ولی در خاکستری دیگر تعداد کانال را مشخص نمیکند و ۲ مقدار دارد
)  تصویر خاکستری را از رنگی تشخیص میدهد. شما میتوانید با استفاده از تصویر خاکستری نتیجه دیگر بگیرید:

import numpy as np
import cv2
image = cv2.imread('carr.jpg',cv2.IMREAD_COLOR)
print(image.shape)
print(image.shape[2])
if image.shape[2] == 2:
print("Gray Image")
elif image.shape[2] == 3:
print("RGB Image")
print(image.size)
print(image.dtype)

۳
RGB Image
۶۵۸۳۵۹
uint8

 

 

تبدیل هندسی تصاویر

تبدیلات (Transformations)

OpenCV دو تابع تبدیل، cv2.warpAffine و cv2.warpPerspective را فراهم می کند که  شما می توانید تمام انواع تبدیلات را داشته باشید. Cv2.warpAffine یک ماتریس تبدیل ۲×۳ را در حالی که cv2.warpPerspective یک ماتریس تبدیل ۳×۳ را به عنوان ورودی می گیرد.

Scaling

 

Scaling  فقط تغییر اندازه تصویر است ،OpenCV ، تابع ()cv2.resize  برای این منظور عرضه می کند.اندازه تصویر را می توان بصورت دستی مشخص کرد، یا می توانید فاکتور مقیاس را مشخص کنید.  روش های مختلفی استفاده می شود.

روش های مختلفی استفاده می شود. روش پیشنهادی cv2.INTER_AREA برای کاهش و (cv2.INTER_CUBIC (slow و cv2.INTER_LINEAR برای بزرگنمایی است. به طور پیش فرض، تابع cv2.INTER_LINEAR برای همه اهداف تغییر اندازه است.

در  کد زیر سایز تصویر را ۲ برابر کردیم:

import cv2
import numpy
import matplotlib.pyplot
image = cv2.imread("car.jpg")
print(image.shape)
# def resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None): # real signature unknown; restored from __doc__
#res = cv2.resize(image,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)
# or
height, width = image.shape[:2]
res = cv2.resize(image,(2*width,2*height), interpolation = cv2.INTER_CUBIC)
cv2.imshow("image",res)
cv2.waitKey(0)
cv2.destroyAllWindows()

Translation 

Translation جابجایی شی از یک مکان به مکان دیگر. اگر می دانید تغییر جهت (x، y)، با اجازه  آن را (tx، ty) قرار می هیم، شما می توانید ماتریس تبدیل M به شرح زیر ایجاد کنید:

 

M = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \end{bmatrix}

Translation

می توانید آن را به یک آرایه Numpy از نوع np.float32  تبدیل و بعد آن را به تابع ()cv2.warpAffine  منتقل کنید. مثال زیر را برای شیفت به مکان (۱۰۰،۵۰) زیر را ببینید:

 

import cv2
import numpy
import matplotlib.pyplot
image = cv2.imread("car.jpg")
print(image.shape)
rows,cols = image.shape[:2]
M = numpy.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(image,M,(cols,rows))
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow("image",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
Translation 

Translation

هشدار
آرگومان سوم تابع ()cv2.warpAffin  اندازه تصویر خروجی است که باید در فرم (عرض، ارتفاع) باشد.
به یاد داشته باشید عرض = تعداد ستون ها، و ارتفاع = تعداد ردیف.

 width = number of columns, and height = number of rows.

Rotation

چرخش یک تصویر برای زاویه تتا به دست می آید توسط ماتریس M تبدیل فرم.

M = \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix}

Rotation

اما OpenCV چرخش مقیاس پذیر با مرکز قابل تنظیم چرخش را فراهم می کند به طوری که شما می توانید در هر مکانی که ترجیح می دهید چرخش دهید.
ماتریس تبدیل اصلاح شده است:

\begin{bmatrix} \alpha & \beta & (1- \alpha ) \cdot center.x - \beta \cdot center.y \\ - \beta & \alpha & \beta \cdot center.x + (1- \alpha ) \cdot center.y \end{bmatrix}

Rotation

 

\begin{array}{l} \alpha = scale \cdot \cos \theta , \\ \beta = scale \cdot \sin \theta \end{array}

Rotation

 

برای پیدا کردن این ماتریس تبدیل، OpenCV تابع cv2.getRotationMatrix2Dرا فراهم می کند، .

 مثال زیر را بررسی کنید که تصویر را به اندازه  ۹۰ درجه میچرخاند:

 

import cv2
import numpy
import matplotlib.pyplot
image = cv2.imread("car.jpg")
print(image.shape)
rows,cols = image.shape[:2]
#or
# rows,cols,_ = image.shape
#or
#rows,cols,ch=image.shape
M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
dst = cv2.warpAffine(image,M,(cols,rows))
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow("image",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

Rotation

Rotation

 

Affine Transformation


در تبدیل شکل ، تمام خطوط موازی در تصویر اصلی هنوز در تصویر خروجی موازی هستند.

برای پیدا کردن ماتریس تبدیل، ما نیاز به سه نقطه از تصویر ورودی و نقاط  متناظر خود را در تصویر خروجی داریم. سپس cv2.getAffineTransform یک ماتریس ۲×۳ ایجاد می شود که به cv2.warpAffine منتقل می شود.

 

import cv2
import numpy
import matplotlib.pyplot
image = cv2.imread("carr.jpg")
print(image.shape)
rows,cols = image.shape[:2]
pts1 = numpy.float32([[50,50],[200,50],[50,200]])
pts2 = numpy.float32([[10,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(image,M,(cols,rows))
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow("image",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
Affine-Transformation

Affine-Transformation

Perspective Transformation

برای Perspective Transformation، شما نیاز به یک ماتریس تبدیل ۳×۳ دارید. خطوط راست هم حتی پس از تغییر نیز باقی خواهند ماند.برای پیدا کردن این ماتریس تبدیل، شما نیاز به ۴ نقطه در تصویر ورودی و نقاط متناظر در تصویر خروجی دارید. ماتریس تبدیل را می توان با عملکرد cv2.getPerspectiveTransform پیدا کرد. سپس cv2.warpPerspective را با این ماتریس تبدیل ۳×۳ اعمال کنید.

کد زیر را ببینید:

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("sudoku-original.jpg")
rows,cols,ch = img.shape
rows,cols,ch = img.shape
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
Perspective-Transformation

Perspective-Transformation



۱-پردازش تصویر با پایتون-OpenCV
۲-آموزش نصب pip در پایتون
۳-
کتابخانه های مورد نیاز پردازش تصویر
۴ – خواندن و نمایش فرمت تصویر در پایتون
۵- نمایش تصویرRGB با Matplotlib و تابع تبدیل ()cvtColor در OpenCv

۶-تغییر فضاهای رنگ- opencv

۷-تقسیم و ادغام کانال های تصویری با opencv

۸-بخشبندی تصویر (Image Segmentation)

۹-آستانه گذاری ساده