پردازش تصویر با پایتون قسمت بیست و هفتم

تبدیل فوریه برای سیگنال یک بعدی

بالاخره رسیدیم به بحث شیرین تیدیل_فوریه

استفاده از تبدیل فوریه برای تجزیه سیگنال نور

 

python-Image processing-Fourier transformation

python-Image processing-Fourier transformation

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

دیجیتال: موجی با تغییرات گسسته(سری  فوریه)

 

 

 

Fourier series

 

Fourier series

 

سیگنال صوت، از مجموعه ای از سينوسها با فرکانس ودامنه وابسته به زمان تشکیل شده است. 

این همه بحث در مورد تبدیل_فوریه و تجزیه سیگنال به فرکانسهای تشکیل دهنده . کاربردش چیه؟؟
یکی از پر کاربردترین موارد استفاده از آن، فرایند فیلتر در پردازش سیگنال است.
مثلا اگر صدا خش دار و بی کیفیت است یا تصویر وضوح خوبی ندارد با حذف برخی از فرکانسها یا کاهش نویز توسط فیلتر به کیفیت مطلوب میرسونیم.

فرکانس یا بسامد: تعداد تکرار یک رویداد در واحد زمان.
بر اساس اینکه کدامیک از این سه نوع فرکانس باید حذف شود، سه نوع فیلتر داریم.

 

python-Image processing-Fourier transformation

python-Image processing-Fourier transformation

 

انواع فیلتر :
۱)فیلتر پایین گذر: فرکانسهای بالاتر از یک مقدار معین را حذف میکند و فرکانسهای پایین تر را عبور میدهد.
۲)میان گذر : فقط فرکانس های حد متوسط و میانی عبور داده میشود.
۳) بالا گذر : فرکانسهای پایین تر از یک مقدار معین را حذف میکند و فرکانسهای بالا تر را عبور میدهد.
واقعیت این است که قبل از پردازش اصلی ما یک پیش پردازش داریم تا سیگنالهای خارج از محدوده ی فرکانسی حذف شود. و این کار با فیلتر کردن انجام میشود.

python-Image processing-Fourier transformation

python-Image processing-Fourier transformation

تا اینجا ما سیگنال یک بعدی را بررسی کردیم.ولی تصویر یک سیگنال دو بعدی است

 

پردازش تصویر با پایتون قسمت بیست و ششم

تفاوت موج و سیگنال

 

برای ادامه بحث به گیف زیر خوب توجه کنید.  کاربرد تبدیل فوریه که یک سیگنال را از حوزه زمان به حوزه فرکانس تبدیل میکند.

 

Fourier_series_and_transform

بعد از توضیح تبدیل سیگنال تک بعدی به حوزه فرکانس، به تبدیل حوزه فرکانسی  سیگنال دوبعدی (تصویر) از حوزه مکانی با استفاده از تبدیل فوریه میپرازیم. فیلتر بالاگذر و پایین گذر  را هم در ادامه بررسی میکنیم.

signal

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

دونوع سگنال داریم:

  1. سیگنال آنالوگ یا پیوسته در دنیای واقعی:  این نوع سیگنال،  شبیه موج در زمان های مختلف مقادیر مختلفی میگیره .
    مانند:
    رادیو، تلفن، تلویزیون های قدیمی و…
  2. سیگنال دیجیتال یا گسسته: در زمانهای مختلف ممکنه مقدار بگیره، ممکنه مقدار نگیره.
    مثل کامپیوترها(۰و۱)

برای تبدیل سیگنال پیوسته به دیجیتال به عنوان مثال سیگنال صوت ( ذخیره و پردازش صدا به صورت دیجیتال در کامپیوتر) باید نمونه برداری (متناوب یا پریودیک) کنیم.

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

photo_2018-06-09_13-26-13

 

wave

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

موج: ارتعاش و نوسانی که اغلب حامل انرژی بوده و در فضا یا فضازمان منتشر می‌شود را «موج» می‌گویند.#ویکی

 

photo_2018-06-09_13-26-21

 

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

photo_2018-06-09_13-26-30

photo_2018-06-09_13-26-39

 

 

پردازش تصویر با پایتون قسمت بیست و پنجم

Smoothing_Images

در مات کردن، یک تصویر ساده، تار و صاف میشود. Blurring، فیلتری در حوزه مکان و پایین گذر است. 
فیلتر های دیجیتال برای مات کردن، لبه دار یا تیز کردن تصاویر دیجیتالی به کار میروند. تیز کردن یعنی جداسازی بین رنگها مشخص شود.

۲D Convolution ( Image Filtering )

اهداف این بخش:

  • مات کردن تصاویر با استفاده از فیلتر های پایین گذر مختلف 
  • اعمال فیلتر های سفارشی بر روی تصاویر (۲D convolution)

همانند سیگنالهای تک بعدی، تصاویر(سگنالهای دو بعدی) را هم میتوان با استفاده از فیلترهای پایین گذر(LPF)، بالا گذر (HPF) و … فیلتر کرد. LPF در برطرف کردن نویز یا تارشدن تصویر کمک می کند. HPF در پیدا کردن لبه ها در یک تصویر کمک می کند. کتابخانه OpenCV با استفاده از تابع ()cv2.filter2D، پیمایش (convolve ) یک هسته با یک تصویر را فراهم میکند.

K =  \frac{1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1  \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \end{bmatrix}

 

 

فیلتر کردن با هسته فوق نتایج زیر را انجام می دهد . عملیات مثل این است:
برای هر پیکسل در تصویر، یک پنجره ۵×۵(کرنل) بر روی این پیکسل متمرکز است، تمام پیکسلهایی که در این پنجره قرار دارند، جمع می شوند و سپس نتیجه به ۲۵ تقسیم می شود. این محاسبه، معادل میانگین مقادیر پیکسل در داخل آن پنجره است. این عمل برای تمام پیکسل ها در تصویر برای تولید تصویر فیلتر شده انجام می شود. این کد را امتحان کنید و نتیجه را بررسی کنید:

 

import cv2
 import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('opencv_logo.png')
kernel = np.ones((5,5),np.float32)/25
dst = cv2.filter2D(img,-1,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Averaging')
plt.xticks([]), plt.yticks([])
plt.show()

یک آرایه۵×۵ که تمام عناصر آن از یک تشکیل شده باشه، توسط دستور زیر انجام میگیره:
np.ones: آرایه ای از ۱ درست میکند:

np.ones((5,5),np.float32)
array([[ 1., 1., 1., 1., 1.],
[ ۱٫, ۱٫, ۱٫, ۱٫, ۱٫],
[ ۱٫, ۱٫, ۱٫, ۱٫, ۱٫],
[ ۱٫, ۱٫, ۱٫, ۱٫, ۱٫],
[ ۱٫, ۱٫, ۱٫, ۱٫, ۱٫]], dtype=float32)

در نهایت تقسیم بر ۲۵ میشود.

اپن سی وی(opencv) این کار را با تابع cv2.filter2D  انجام میدهد.

cv2.filter2D(img,-1,kernel)

همانطور که مشاهده میکنید این تابع ۳ پارمتر دارد:

 

cv.filter2D (src, dst, ddepth, kernel, anchor = new cv.Point(-1, -1), delta = 0, borderType = cv.BORDER_DEFAULT)

کل پارامترهایی که این تابع میگیره اینها هستن.

۱) src: تصویر ورودی
۲) dst : تصویر خروجی که از نظر اندازه و تعداد کانال با تصویر ورودی یکی است
۳) ddepth: عمق دلخواه تصویر خروجی
۴)کرنل
۵)و….

اگر عمق -۱ باشد یعنی عمق تصویر خروجی باید مانند تصویر ورودی باشد.تصویر ورودی میتونه هر تعداد کانال داشته باشه که به صورت جداگانه پردازش شوند ولی عمق باید  CV_8U, CV_16U, CV_16S, CV_32or  CV_64باشد

دقتdepth :تعداد بیتهای در نظر گرفته شده برای هر پیکسل در کامپیوتر
توجه کنید اگر ddepth مقدار -۱ بگیرد یعنی نتیجه نوع داده تصویر خروجی برابر تصویر ورودی است مثل np.uint8 یعنی ۸بیت ۰-۲۵۵(cv2.CV_8U )
الان تصویر ورودی من دارای اطلاعات زیر میباشد:

img = cv2.imread(‘face.png’)
»> img.dtype
dtype(‘uint8’)

در opencv ،  هر پیکسل در تصویر رنگی،  نماینده ۳ پارامتر(کانال) است: آبی، سبز و قرمز. هر کدام از این پارامتر ها مقدار ۰-۲۵۵ میگیرند. به طور مثال آبی مطلق :

b g r
۲۵۵ ۰ ۰

87

 

تارشدگی تصویر (صاف کردن تصویر)

برای حذف نویز مفید است. در واقع محتوای فرکانس بالا را حذف می کند (به عنوان مثال: نویز، لبه ها)، بنابراین لبه ها ، دچار تغییرات خیلی کمی میشوند .

OpenCV تقریبا چهار نوع تکنیک صاف کردن تصویر را فراهم می کند.

۱)Averaging

این کار توسط پیمایش یک فیلتر جعبه(کرنل) نرمال شده با تصویر ورودی، با استفاده از  cv2.blur () یا cv2.boxFilter () انجام می شود. ما باید عرض و ارتفاع هسته را مشخص کنیم. یک فیلتر جعبه نرمال شده ۳ × ۳ مانند زیر می باشد:

 

7e

import cv2
import numpy as np
from matplotlib import pyplot as plt>
img = cv2.imread('8.png')
blur = cv2.blur(img,(5,5))
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()

9

۲) Gaussian Blurring

اینجا به جای فیلتر جعبه، از هسته گوسی  استفاده میشود. تابع مورد استفاده، cv2.GaussianBlur() میباشد. باید عرض و ارتفاع هسته را  که مثبت و فرد است، مشخص کنیم :

blur = cv2.GaussianBlur(img,(5,5),0)

10

 

۳) Median Blurring

بسیار موثر در برابر نویز نمک و فلفل در تصاویر است.  به طور موثر نویز را کاهش می دهد. هسته آن اندازه باید یک عدد صحیح عدد صحیح باشد.

 median = cv2.medianBlur(img,5)

 

13

 

 

 

۴) Bilateral Filtering

فیلتر دو طرفه توسط تابع،   ()cv2.bilateralFilter ، در حذف نویز با حفظ لبه ها بسیار موثر میباشد.

import cv2
 import numpy as np
 from matplotlib import pyplot as pltimg = cv2.imread('14.png')
 temp = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
 blur = cv2.bilateralFilter(temp,9,75,75)plt.subplot(121),plt.imshow(temp),plt.title('Original')
 plt.xticks([]), plt.yticks([])
 plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
 plt.xticks([]), plt.yticks([])
 plt.show()

15

ببینید، بافت روی سطح رفته است، اما لبه ها هنوز هم حفظ می شوند. 

https://commons.wikimedia.org/wiki/File:3D_Convolution_Animation.gif

پردازش تصویر با پایتون قسمت بیست و چهارم

Convolution

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

۱٫کانولوشن حوزه مکان

 

یکی از عملگر  های مهم در پردازش تصویر و سیگنال،  کانولوشن است که برروی دو سیگنال یک بعدی یا دو بعدی عمل میکند:  یعنی  می توانید یک سیگنال (یا تصویر) را به عنوان ورودی  و دیگری ( هسته)  را به عنوان فیلتر روی تصویر ورودی، در نظر بگیرید که سرانجام  باعث  تولید تصویر خروجی میشود.
(بنابراین کانولوشن دو عکس را به عنوان ورودی می گیرد و تصویر سومی را  به عنوان خروجی  تولید می کند. )
کانولوشن در حوزه مکان عملگر ضرب هم معنی میشود. در واقع  یک مفهوم فوق العاده مهم در بسیاری از زمینه های ریاضی و مهندسی (از جمله بینایی کامپیوتر است).

کانولوشن بر روی سیگنال یک بعدی را  مشاهده میکنید :

 

jjure

 

 می توانیم کانولوشن را در سیگنالهای ۲D نیز  اعمال کنیم. برای کانولوشن ۲D، هسته  روی هر پیکسل از  تصویر حرکت میکندیعنی پیمایش میکند  و عمل ضرب  تصویر ورودی و هسته، و اضافه کردن آنها – نتیجه ارزش جدیدی از تصویر است.

این قسمت یک مثال ساده از کانولوشن  در فضایی ۲D است. تعریف کانولوشن ۲D و چگونگی پیمایش در ۲D در اینجا توضیح داده شده است.

 

 

 

 

x[m,n]

ورودی

h[m,n]

هسته

y[m,n]

خروجی

 

 

 

 

 

 

 

 

 


 

 

y[0,0]y[0,0]

y[1,0]y[1,0]

y[2,0]y[2,0]

y[1,1]y[1,1]

y[2,1]y[1,1]

y[2,1]y[2,1]

y[0,2]y[0,2]

y[1,2]y[1,2]

y[2,2]y[2,2]

../_images/numerical_no_padding_no_strides.gif

پردازش تصویر با پایتون قسمت بیست و سوم

 

 

Background Subtraction

 

تفریق تصویر

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

چندین الگوریتم برای این منظور معرفی شدند. OpenCV سه الگوریتم را اجرا کرده است که بسیار آسان است. ما آنها را توسط فیلم زیر،  یک به یک می بینیم.

 

 

https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi

 

BackgroundSubtractorMOG

import numpy as np
import cv2
cap = cv2.VideoCapture('vtest.avi')
fgbg = cv2.createBackgroundSubtractorMOG()
while(1):
    ret, frame = cap.read()
    fgmask = fgbg.apply(frame)
    cv2.imshow('frame',fgmask)
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()
resmog

 

BackgroundSubtractorMOG2

import numpy as np
import cv2
cap = cv2.VideoCapture('vtest.avi')
fgbg = cv2.createBackgroundSubtractorMOG2()
while(1):
    ret, frame = cap.read()
    fgmask = fgbg.apply(frame)
    cv2.imshow('frame',fgmask)
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()
https://docs.opencv.org/3.3.0/db/d5c/tutorial_py_bg_subtraction.html

https://docs.opencv.org/3.3.0/db/d5c/tutorial_py_bg_subtraction.html

 

BackgroundSubtractorGMG

import numpy as np
import cv2
cap = cv2.VideoCapture('vtest.avi')
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
fgbg = cv2.createBackgroundSubtractorGMG()
while(1):
    ret, frame = cap.read()
    fgmask = fgbg.apply(frame)
    fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
    cv2.imshow('frame',fgmask)
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()
 
resgmg

پردازش تصویر با پایتون قسمت بیست و دوم

Histogram in OpenCv

 نمودار هیستوگرام چیست؟

هیستوگرام یا بافت‌نگار به نموداری گفته می‌شود که فراوانی عناصری که در محور افقی آن قرار دارند را در محور عمودی نشان می‌دهد. ویکی

تصویر زیر یک ماتریس دو بعدی از یک تصویر است که که حاوی اطلاعات از شدت روشنایی است .اگر فرض کنیم، تعداد پیکسلهایی که شدت روشنایی مثلا ۰ دارند ۱۰ تا است، ۱۰ را در محور y و محدوده شدت روشنایی(۰ یا سیاه) را درمحور x نشان میدهد.
یک هیستوگرام  مجموعه ای از مناطق مستطیل شکل یا استوانه ای به نام سطل(bin) است. (تعریف دیگر)

 

https://docs.opencv.org

https://docs.opencv.org

اگر بخواهیم این داده ها را به صورت سازمان یافته ببینیم  باید چه کنیم؟ با توجه به اینکه محدوده ارزش اطلاعات برای این مورد ۲۵۶ مقدار است، میتوانیم محدوده را به بخشهایی مثل سطل(bins) تقسیم کنیم:

\begin{array}{l} [0, 255] = { [0, 15] \cup [16, 31] \cup ....\cup [240,255] } \\ range = { bin_{1} \cup bin_{2} \cup ....\cup bin_{n = 15} } \end{array}

 

بنابراین  می توانیم تعداد پیکسل هایی را که در محدوده هر سطل قرار می گیرند، نگهداریم. برای تصویر بالا، تصویر زیر آماده شده است. محور x همان سطل ها و محور y تعداد پیکسل.

../../../../../_images/Histogram_Calculation_Theory_Hist1.jpg

این یک مثال ساده از نحوه عملکرد هیستوگرام و دلیل مفید بودن آن است. هیستوگرام می تواند نه تنها از شدت های رنگ،  بلکه از ویژگی های تصویری که می خواهیم اندازه گیری کنیم (مانند شیب، جهت ها و غیره) باشد. 

بیایید برخی ورودی های تابع  هیستوگرام را شناسایی کنیم:

  • dims: تعداد پارامترهایی که می خواهید اطلاعات را جمع آوری کنید. در مثال ما مقدار این پارامتر ۱ است. چون فقط مقدار شدت روشنایی را در نظر گرفتیم. 
  • bins : تعداد هر مستطیل یا سطل را مشخص میکند. در این مثال bins = 16
  • range: بازه ای از مقادیر [range = [0,255

اگر می خواهید دو ویژگی را حساب کنید چه؟ در این حالت نتیجه شما یک قطعه ۳D است. همین کار را برای ویژگی های بیشتر اعمال می کند (مطمئنا پیچیده تر می شود).

در تمام قسمت ها از تصویر زیر به عنوان ورودی استفاده شده است:

https://en.wikipedia.org/wiki/File:SunLou2.jpg

https://en.wikipedia.org/wiki/File:SunLou2.jpg

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

gray_img = cv2.imread('images_histogram.png', cv2.IMREAD_GRAYSCALE)#histogram tasvir tak kanale
cv2.imshow('GoldenGate',gray_img)
hist = cv2.calcHist([gray_img],[0],None,[256],[0,256])
plt.hist(gray_img.ravel(),256,[0,256])
plt.title('Histogram for gray scale picture')
plt.show()

while True:
    k = cv2.waitKey(0) & 0xFF     
    if k == 27: break             # ESC key to exit 
cv2.destroyAllWindows()

hisgray

image_histogram

نکته: نحوه کارکرد تابع ()ravel, همانند (reshape(-1.

>>> import numpy as np
>>> x = np.array([[1, 2, 3], [4, 5, 6]])
>>> print (np.ravel(x))
[۱ ۲ ۳ ۴ ۵ ۶]
>>> x.reshape(-1)
array([1, 2, 3, 4, 5, 6])
>>>

()calcHist

OpenCV از  تابع ()cv2.calcHist  برای هیستوگرام استفاده میکند. بنابراین، زمان آن است که به پارامترهای خاص مربوط به تابع () cv2.calcHist نگاه کنیم:

cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])

 

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

hist = cv2.calcHist([gray_img],[0],None,[256],[0,256])

پارامتر ها

  1. images: تصویر منبع از نوع uint8 یا float32، باید به عنوان یک لیست ارائه شود. [gray_img]
  2. channels: این مورد نیز به عنوان یک لیست [] داده شده است. این شاخص کانال است که ما با آن هیستوگرام را محاسبه می کنیم. برای مثال، اگر ورودی تصویر سیاه و سفید است، مقدار آن [۰] است. برای تصویر رنگی، می توانید [۰]، [۱] یا [۲] را به ترتیب برای هیستوگرام کانال آبی، سبز یا قرمز محاسبه کنید.
  3. mask:  برای پیدا کردن هیستوگرام  تصویرکامل ، آن را به عنوان None تنظیم شده است. با این حال، اگر ما می خواهیم هیستوگرام منطقه خاص تصویر را دریافت کنیم، باید یک تصویر ماسک برای آن ایجاد کنیم و آن را ماسک کنیم.
  4. histSize:  نشان دهنده شمارش BIN است. باید در [] داده شود. برای مقیاس کامل، ما [۲۵۶]را قرار دادیم .
  5. ranges : به طور معمول، [۰،۲۵۶] است.

 

()NumPy – np.histogram

 

همچنین NumPy یک تابع برای هیستوگرام، که ()np.histogram  است  را فراهم می کند. بنابراین، ما می توانیم به جای تابع OpenCV از NumPy استفاده کنیم:

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

gray_img = cv2.imread('hisimage.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow('GoldenGate',gray_img)
#hist = cv2.calcHist([gray_img],[0],None,[256],[0,256])
hist,bins = np.histogram(gray_img,256,[0,256])

plt.hist(gray_img.ravel(),256,[0,256])
plt.title('Histogram for gray scale picture')
plt.show()

while True:
    k = cv2.waitKey(0) & 0xFF     
    if k == 27: break             # ESC key to exit
cv2.destroyAllWindows()

هیستوگرام برای تصاویر رنگی

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

img = cv2.imread('images/GoldenGateSunset.png', -1)
cv2.imshow('GoldenGate',img)

color = ('b','g','r')
for channel,col in enumerate(color):
    histr = cv2.calcHist([img],[channel],None,[256],[0,256])
    plt.plot(histr,color = col)
    plt.xlim([0,256])
plt.title('Histogram for color scale picture')
plt.show()

while True:
    k = cv2.waitKey(0) & 0xFF     
    if k == 27: break             # ESC key to exit 
cv2.destroyAllWindows()

hiscolorimage

 

متعادل سازی هیستوگرام


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

یک تصویر را که مقادیر پیکسل(شدت روشنایی) آن،  به رنج کمی از مقادیر،  محدود است را در نظر بگیرید. برای مثال، تصویر روشن تر تمام پیکسل ها را به مقادیر بالا(نزدیک به ۲۵۵) محدود خواهد کرد. اما یک تصویر خوب، پیکسل ها را از تمام نقاط تصویر انتخاب میکند.

بنابراین باید این هیستوگرام را به هر دو انتها ببرید ( تصویر زیر از ویکیپدیا داده شده است) و این همان کاری است که متعادل سازی  هیستوگرام می کند (به صورت ساده).

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

 

histogram_equalization.png

importcv2
import numpy as  np
from matplotlib import pyplot as plt
img = cv2.imread('wiki.jpg',0)
hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max()/ cdf.max()
plt.plot(cdf_normalized, color = 'b')
plt.hist(img.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()

 

  
 

در تصوير، مقدار ميانگين مقدار متوسط شدت روشنايی تصوير را نشان می دهد و مقدار واريانس، مقدار متوسط کنتراست تصوير را نمايش می دهد.

 
 🆔@image_Process
🌐https://t.me/image_Process

تشخیص پلاک خودروهای های ایرانی توسط کتابخانه OpenCV

بعد از تمام  شدن آموزش مقدماتی پردازش تصویر، پروژه های کوچک وبعد  پروژه تشخیص پلاک خودرو را بررسی میکنیم. 

 

🌟تشخیص حیوانات🌟

g1

2g

🌟تشخیص چهره🌟

g4

🌟تشخیص بارکد🌟

g5

‍ 🌟Credit card OCR🌟

g7

 

 

🌟تشخیص پلاک خودرو🌟

g8

 

 

🆔@image_Process
🌐https://t.me/image_Process

تفاوت حوزه مکانی و فرکانسی

پردازش تصویر با پایتون قسمت بیست و یکم

تفاوت فیلتر کردن حوزه مکان با فرکانس

 

image

مراحل پایه در پردازش تصویر:
۱) پیش پردازش
۲) بخش بندی
۳) توصیف و نمایش

۴)تشخیص و تفسیر

 پردازش تصویر: فرایند دستکاری یا انجام تغییرات مناسب بر رو ی تصویر(سیگنال دو بعدی)، جهت :

۱)  درک بهتر برای انسان
۲)  درک کامپیوتر (بینایی ماشین)

 تصویر خاکستری تابعی از شدت روشنایی است :

f(x,y)= 0-255

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

 

وقتی تصویر را از ورودی(دوربین) گرفتیم: نمونه برداری میکنیم تا تصویر به پیکسل های جدا از هم تقسیم شود.
برای نمونه برداری جهت دیجیتالی کردن تصویر، اگر ورودی ها را دیجیتالی کنیم به آ ن نمونه برداری میگویند.
اگر خروجی تابع را دیجیتالی کنیم به آن کوانتیزه کردن میگویند.
با ایجاد تصویر دیجیتالی میتوانیم فرض کنیم یک ماتریس دو بعدی داریم.
 پیش پردازش: در این مرحله،  تصویر را با حذف نویز ها یا بالا بردن کنتراست و… ارتقا میدهیم. با بالا رفتن کیفیت تصویر، هم استفاده ی راحتر برای انسان فراهم شده و هم بقیه پردازش ها ، بهتر انجام میشود.

filter2
 برای بهبود و ارتقا کیفیت تصویر ، دو روش داریم:

۱) حوزه مکانی (Spatial Domain)
۲) حوزه فرکانسی

 در حوزه مکان، پردازش ها و عملیات بر روی پیکسلها انجام میشود و یک تصویر با مشاهده سطح خاکستری توصیف میشود که به دو صورت است:

🔶فیلترهای مکانی بر روی ورودیها یا موقعیت مکانی تابع f(x,y) ،که با توجه به پیکسلهای همسایه انجام میشود. فیلتر ها به دو دسته خطی و غیر خطی هستند. فیلترهای مکانی، فیلتر هایی که اندازه تغییرات تصویر را مانند بالاگذر (تغییرات زیاد) یا پایین گذر (تغییرات کم) و … حذف میکنند.
🔸🔸 پایین گذر(مات و نرم کردن): تغییرات زیاد را حذف و تغییرات کم را رد میکند
خطی
۱) فیلتر میانگین: مقدار پیکسل های همسایه جایگزین پیکسل مرکزی میشود.(کانولوشن).
۲)گوسی .

غیرخطی:
۱)میانه
و …
🔸🔸 بالا گذر(تیز و لبه دار کردن) : تغییرا ت کم را حذف و تغییرات زیاد را رد میکند.
۱) لاپلاسین
۲) سوبل
۳)و ….

🔶 تبدیلات بر روی خروجی تابع که نور یا شدت روشنایی نامیده میشود، انجام میشو د. در واقع تبدیلات بدون توجه به پیکسل های همسایه انجام میشود. تبدیلات بر روی شدت روشنایی (تبدیلات مکانی)شامل موارد زیر میباشد:

۱) تعدیل هیستوگرام یا Histogram Equalization
۲) تفریق (subtraction )
و ….

۲) در حوزه فرکانس، تصویر را با استفاده از تبدیل فوریه به حوزه فرکانس میبریم.

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

در این حوزه  ما دیگر اطلاعات مکانی نداریم، یعنی نمیتوانیم بگوییم کجا به کجای تصویر مربوط است. ولی یک سری اطلاعات ارزشمند بدست می آوریم.
حوزه فرکانس، تفاوت پیکسلهای کنار همدیگر را به صورت نموداری در نظر میگیرد و توسط یک سری موجهای سینوسی و کسینوسی شبیه سازی میکند.
و همین امر باعث میشود نویز های مانند پریودیک که در حوزه مکان قابل حذف نیستند، حذف شوند. یعنی در حوزه فرکانس به صورت نقاطی سفید دیده میشوند که با ۰ یا سیاه کردن آن نقاط، ازبین میروند.


pri
نکته
** این دو حوزه قابل تبدیل به یکدیگر هستند.
** برخی فیلتر ها در هر دو حوزه قابل اعمال هستند.

🆔@image_Process
🌐https://t.me/image_Process

پردازش تصویر با پایتون قسمت بیستم

Otsu’s Binarization (تقسیم بندی Otsu)

در این روش قرار است از خروجی دوم روش آستانه گیری ساده، retVal استفاده کنیم. چرا ما از این روش استفاده میکنیم؟?؟
در آستانه گیری ساده ما از یک مقدار سراری استفاده کردیم. ولی از کجا بدونیم این مقدار، یک مقدار خوب و بهینه است؟  بله. با آزمون و خطا.

روش آستانه گذاری Otsu ، تصویر را به گونه ای تقسیم بندی میکند که تصویر با بهترین مقدار آستانه به دو کلاس سیاه و سفید یا پیش زمینه و پس زمینه یا پس زمینه و شی تقسیم میشود:

در یک تصویر bimodal (تصویری که هیستوگرام آن دارای دو قله میباشد)، تقریبا در وسط قله ها میتوان آستانه بهینه را انتخاب کرد.

برای همین ما از تابع cv2.threshold() استفاده میکنیم ولی یک فلگ اضافی ، cv2.THRESH_OTSU را داریم . این روش مقدار بهینه آستانه را در retVal قرار میدهد و مقدار threshold برابر ۰ میشود.

 

 

noisy_leaf

تصویر اصلی نویز دار

 

 

otsu

otsu

 

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

img = cv2.imread('bimodal_hsv_noise.png',0)

# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
          'Original Noisy Image','Histogram',"Otsu's Thresholding",
          'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]

for i in xrange(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()

تک آستانه، دو سطحی

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

 

 

photo_2018-01-25_15-53-55

آستانه گذاری دوسطحی ، تک آستانه

 

آستانه گذاری دوسطحی یک مقدار آستانه دارد و پیکسلهای تصویر به دو گروه یا کلاس تقسیم میشوند. انتخاب آستانه در این گروه تصاویر بسیار ساده از آستانه گذاری چند سطحی میباشد.

 

 

 

آستانه گذاری چند سطحی با چند آستانه

 

تصویری که بیش از یک آستانه دارد، آستانه گذاری چند سطحی میباشد. 

sample

تصویر اصلی

photo

آستانه گذاری چند سطحی با دو آستانه

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('sample.jpg',0)
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
images = [img, 0, th1,
img, 0, th2,
blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
'Original Noisy Image','Histogram',"Otsu's Thresholding",
'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in xrange(3):
plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()

🆔@image_Process
https://t.me/image_Process

پردازش تصویر با پایتون قسمت نوزدهم

Adaptive Thresholding

در روش Simple Thresholding،  تصاویری که دارای روشنایی متفاوت در قسمتهای مختلف میباشند خروجی جالبی ندارند. ولی در آستانه گذاری تطبیقی یا سازگاری، بر خلاف آستانه گذاری ساده، مقدار آستانه در هر مکان پیکسل، بستگی به شدت روشنایی پیکسلهای همسایه دارد. در واقع مقدار آستانه برای ناحیه ی کوچکی از تصویر محاسبه میشود و ما دارای آستانه های متفاوت زیادی میباشیم.پیش فرض  این است که مناطق کوچکتر تصویر، احتمال بیشتری برای روشنایی یکنواخت دارند، بنابراین برای آستانه گذاری بیشتر مناسب هستند.

**** برای محاسبه استانه محلی مراحل زیر طی میشود:****

۱) یک بلوک یا ناحیه bxb، اطراف مکان پیکسل توسط کاربر انتخاب میشود.b=3,5,7,…

۲) میانگین وزنی ناحیه bxb را محاسبه میکنیم. Opencv دو روش پیشنهاد میدهد:

— محاسبه میانگین ناحیه پیکسل  ناحیه bxb

— محاسبه میانگین وزنی گوسی مکان پیکسل ناحیه bxb

۳) برای محاسبه مقدار آستانه، میانگین  از یک مقدر ثابت(C) کم میشود:

 T= M- C

توابع ساده و سریع عبارتند از:

میانگین (mean) توزیع شدت محلی:

Eqn:eqnadp1

مقدار میانه(median )

Eqn:eqnadp2

یا میانگین حداقل و حداکثر مقادیر

Eqn:eqnadp3

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

 

threshold
از آنجا که این تصویر حاوی گرادیان روشنایی قوی است، آستانه سراسری، نتایج بسیار بدی را به وجود می آورد، همانطور که دیده می شود:

import cv2
import numpy as np
img = cv2.imread('sample.jpg')
ret,threshold1 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
cv2.imshow('threshold ',threshold1)
cv2.waitKey (0)
cv2.destroyAllWindows ()

ad

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

cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst]) -> dst

این تابع تنها یک خروجی دارد و ورودی های آن به صورت زیر است:

src: تصویر ورودی

maxval: حداکثر مقدار ، که می تواند به خروجی اختصاص داده شود.

Adaptive Method :  نوع آستانه

cv2.ADAPTIVE_THRESH_MEAN_C: مقدار آستانه،  برای وزن متوسط تنظیم شده است.

cv2.ADAPTIVE_THRESH_GAUSSIAN_C: مقدار آستانه ، مجموعه ای از مقادیر ناحیه ای است که وزن آنها یک پنجره گاوسی است.

blockSize  : اندازه ناحیه ی همسایگی را تعیین میکند.

C: c، یک ثابت است که از میانگین یا میانگین وزنی کم میشود. 

dst :تصویر خروجی(باینری)

 import cv2
 import numpy as np
 from matplotlib import pyplot as plt
img = cv2.imread('sample.jpg',0)
img = cv2.medianBlur(img,5)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
 th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2)
 th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
 titles = ['Original Image', 'Global Thresholding (v = 127)','Adaptive Mean Thresholding',
 'Adaptive Gaussian Thresholding']
 images = [img, th1, th2, th3]
 for i in xrange(4):
 plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
 plt.title(titles[i])
 plt.xticks([]),plt.yticks([])
 plt.show()
Adaptive Thresholding

Thresholdh

تفاوت آستانه ساده با تطبیقی در این تصویر مشهود است.

آستانه گذاری ساده، از آستانه ثابت برای تمام پیکسل های تصویر استفاده می کند، بنابراین، تنها اگر هیستوگرام شدت تصویر ورودی، دارای پیک های جدا شده، مربوط به شی(ها) و پس زمینه مورد نظر باشد، کار می کند. از این رو، نمی تواند با تصاویری که حاوی، gradient روشنایی قوی باشد، مقابله کند.

از سوی دیگر، آستانه گذاری تطبیقی محلی، یک آستانه منحصربه فردی را برای هر پیکسل بر اساس محدوده ای از میزان شدت در همسایگی محلی انتخاب می کند. این آستانه گذاری، برای  تصاویری که هیستوگرام شدت روشنایی، دارای قله های متمایز نباشد(مانند:بخش بندی متن از تصویر)، مناسب است.

این روش در ناحیه اطراف متن نتیجه بخش است. زیرا پیکسل های پیش زمینه وپس زمینه در محدوده همسایگی هر پیکسل به اندازه کافی وجود دارد.
با این حال در margin(ناحیه اطراف متن)،  میانگین ناحیه محلی به عنوان یک آستانه مناسب نیست، زیرا محدوده مقادیر شدت در همسایگی محلی، بسیار کوچک است و میانگین نزدیک به پیکسل مرکزی است. این وضعیت را می توان بهبود داد، اگر آستانه مورد استفاده  mean نباشد مگر  (mean-C)،  که C یک ثابت است.
بنابراین  تمام پیکسلهایی که در محدوده ی یکسان وجود دارند (به عنوان مثال در امتداد حاشیه) به پس زمینه تنظیم میشود.
نتیجه ۷ × ۷ همسایگی و C = 7 نشان داده شده است :

 

11

12

تاثیر انتخاب  cوb های متفاوت در تصویر خروجی.
میتوان به اهمیت این دو ورودی پی برد.