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

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

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

 

مرسوم ترین خصوصیت تصویر برای  آستانه گذاری، سطح  خاکستری پیکسل است:
اگر T آستانه باشد

g(x,y) = ۰ if f(x,y) < T  و g(x,y) = ۱ if f(x,y) ≥ T

اگر دو تا آستانه داشته باشیم  T1 < T1  :

g(x,y) = ۰ if f(x,y) < T1 OR f(x,y) > T2 and g(x,y) = ۱ if T1 ≤ f(x,y) ≤ T2

th8

https://www.cs.auckland.ac.nz

 

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

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

تابع استفاده شده، cv2.threshold است.

 

cv2.threshold(src, thresh, maxval, type[, dst]) → retval, dst

پارامترها

src : آرایه ورودی همان تصویر ورودی( تک کاناله(خاکستری )، ۸ بیتی یا ۳۲ بیتی شناور)

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

thresh : مقدار آستانه

maxval : حداکثر مقدار برای استفاده دو نو آستانه گذاری ساده THRESH_BINARY و THRESH_BINARY_INV .

type  : نوع آستانه گذاری

 

OpenCV سبک های مختلف آستانه گذاری ساده  را فراهم می کند و توسط پارامتر چهارم تابع تعیین می شود:

  • cv2.THRESH_BINARY
  • cv2.THRESH_BINARY_INV
  • cv2.THRESH_TRUNC
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZERO_INV
threshold ture

https://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#cv2.threshold

 

ساده ترین شکل آستانه گذاری ، آستانه گذاری باینری نامیده می شود.

اگر (src (x، y بزرگتر از thresh باشد، مقدار (dst (x، y(تصویر مقصد) به maxValue تنظیم میشود، در غیر اینصورت آن را صفر تنظیم می کند.

ifsrc(x,y) > thresh
dst(x,y) =maxValue
else
dst(x,y)  =0
thresholded
 

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

 دو خروجی به دست می آید.یکی از آنها retval  است که بعدا توضیح داده خواهد شد.خروجی دوم تصویر آستانه ای است. بنابراین حتما باید از دو متغیر استفاده کنیم. 

threshold

https://www.learnopencv.com

کد:

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

img = cv2.imread('threshold.png')
#thresh = ۰ و maxValue = ۲۵۵٫
ret,thresh1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY)
#با تغییر آستانه به ۳۵، شدت نور بالاتر از  ۳۵ نمایش داده میشود. 
ret,thresh2 = cv2.threshold(img,35,255,cv2.THRESH_BINARY)
ret,thresh3 = cv2.threshold(img,65,255,cv2.THRESH_BINARY)
#با آستانه ۱۲۷ و بیشترین مقدار ۱۲۵ ، شدت نور بالاتر از ۱۲۷ و با رنگ ۱۲۸ نمایش داده میشود. 
ret,thresh4 = cv2.threshold(img,127,128,cv2.THRESH_BINARY)
ret,thresh5 = cv2.threshold(img,0,128,cv2.THRESH_BINARY)

titles = ['Original Image','THRESH1','THRESH12','THRESH3','THRESH4','THRESH6']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):
 plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
 plt.title(titles[i])
 plt.xticks([]),plt.yticks([])

plt.show()

th1
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('threshold.png')
ret,thresh1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY)
# تغییر بیشترین مقدار به ۱۲۸، مقدار بخش آستانه گذاری شده را به ۱۲۸ تنظیم می کند.
ret,thresh2 = cv2.threshold(img,0,128,cv2.THRESH_BINARY)
ret,thresh3 = cv2.threshold(img,0,201,cv2.THRESH_BINARY)
ret,thresh4 = cv2.threshold(img,0,66,cv2.THRESH_BINARY)
ret,thresh5 = cv2.threshold(img,0,33,cv2.THRESH_BINARY)
titles = ['Original Image','THRESH255','THRESH128','THRESH201','THRESH6','THRESH33']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
th33

Image Segmentation

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

OpenCV Threshold

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

هدف پردازش تصویر دیجیتال، استخراج اطلاعات مفید(آبجکت، شی، ۲۵۵، ۱، روشن) از تصاویر، بدون کمک انسان است.

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

 

 

خروجی بخشبندی

 

۱) پیکسلهای لبه یا مرز یک بخش. کاربرد:  گوشه ها یا حالت  ناحیه ی مد نظر  را مشخص میکند.

۲) تمام پیکسلهای درون یک بخش. کاربرد: ویژگیهای درونی بخش های تصویر مثل بافت، رنگ و … را مشخص میکند.

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

 

تکنیکهای بخشبندی

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

Contexuall

۲) non-contextual (بخش بندی بر اساس نواحی): بر اساس شباهت سطوح خاکستری ، تصویر،  در ابتدا با آستانه گذاری، ناحیه را گسترش داده و با ادغام کردن  بخش ها، بخشبندی میشود. همین جا اشاره کنم که آستانه گذاری از نوع non-contextual میباشد.(ماسکهای آشکار ساز لبه ها، همانند فیلتر بالاگذر حوزه فرکانس  که در قسمتهای بعدی توضیح داده میشوند، میباشند.)

non

 

کاربرد بخشبندی

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

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

 

آستانه‌گذاری  مناسب‌ترین و ساده ترین تکنیک بخش بندی non-contextual است.
با اعمال آستانه‌گذاری بر روی تصویر در مقیاس خاکستری، تصویری باینری(۰و۱) بدست می‌آید که تصویر به دو بخش کاملا جدا از هم تقسیم میشود.یکی از آنها حاوی پیکسل هایی با مقادیر داده ورودی کوچکتر از آستانه و دیگری مربوط به مقادیر ورودی است که برابر آستانه یا بیشتراز آن هستند. مناطق اول و دوم معمولا به ترتیب با برچسب صفر (۰) و غیر صفر (۱) برچسب گذاری می شوند. آستانه گذاری ، ممکن است دارای چند آستانه باشد که تصویر را به چند بخش مجزا تقسیم میکنند.

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

به عبارت دیگر آستانه گذاری شامل تقسیم یک تصویر به دو منطقه است: یک منطقه آبجکت و یک منطقه پس زمینه.
threshold e

تصویر زیر را با دقت مشاهده کنید:

threshold

https://www.learnopencv.com

چند عدد می بینید؟
اکثر شما اعداد زیر را می بینید:
۳۲ (آه، بله، به دقت نگاه کنید)، ۶۴، ۱۰۰، ۱۲۸، ۱۸۰، ۲۰۰ و ۲۵۵٫ اما در تصویر، اعداد بیشتری وجود دارد که به چشم نمیاد.

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

در حقیقت تمام اعداد در تصویر اصلی یک مقدار خاکستری  برابر با عدد دارند. بنابراین ۲۵۵ روشنترین و ۵ تاریک ترین است.

 خواندن اعداد در تصویر آستانه گذاری شده  آسان تر از خواندن اعداد در تصویر اصلی است. جای تعجب نیست که یک الگوریتم  تصویر آستانه گذاری شده، بسیار ساده تر از تصویر اصلی،  پردازش می کند.
تمام الگوریتم های آستانه گذاری، یک تصویر منبع (src) و مقدار آستانه (thresh) به عنوان ورودی میگیرند، و با مقایسه مقادیر پیکسل در پیکسل  تصویر منبع (x، y) با آستانه،  یک تصویر خروجی (dst) تولید می کند. اگر src (x، y)> thresh باشد، سپس (dst (x، y یک مقدار را تعیین می کند. در غیر این صورت، (dst (x، y مقدار دیگری را ایجادمی کند.

سه روش آستانه ‘گذاری داریم که در قسمتهای بعدی توضیح داده خواهند شد:
+ Simple thresholding
+ Adaptive thresholding
+ Otsu’s thresholding

 

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

 

Grayscale(خاکستری)

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

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

http://hamamatsu.magnet.fsu.edu

تصاویر خاکستری فقط دارای یک کانال رنگی(۸بیتی) در مقیاس ۰ تا ۲۵۵ هستند که نشان دهنده روشنایی آن پیکسل است، ۰ کاملا تاریک (سیاه) و ۲۵۵ کاملا روشن (سفید) است.


87

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

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

مثلا به رنگ سبز دقت کنید، فقط قسمتی که رنگ سبز داریم سفید وبقیه قسمتها سیاه است. کانال سبز  یک کانال ۸ بیتی که به صورت   [۰,۲۵۵,۰]:rgb مقدار دهی میشود و نشان دهنده این است که هر چه شدت نور به سمت ۲۵۵ باشد رنگ سبز بیشتر و هر چه به سمت ۰ باشد رنگ سبز کمتری داریم و در مورد کانالهای دیگر هم همین استدلال را میشه کرد.

Capture

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

import numpy as np
import cv2
import matplotlib.pyplot as pltimg = cv2.imread(‘test.jpg’)
gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
#تصویر خاکستری به عنوان آراه ای دوبعدیprint(gray_img)
[[۲۵۰ ۲۵۰ ۲۵۰ …, ۲۵۰ ۲۵۰ ۲۵۰]
[۲۵۰ ۲۵۰ ۲۵۰ …, ۲۵۰ ۲۵۰ ۲۵۰]
[۲۵۰ ۲۵۰ ۲۵۰ …, ۲۵۰ ۲۵۰ ۲۵۰]
…,
[۲۵۰ ۲۵۰ ۲۵۰ …, ۲۵۰ ۲۵۰ ۲۵۰]
[۲۵۰ ۲۵۰ ۲۵۰ …, ۲۵۰ ۲۵۰ ۲۵۰]
[۲۵۰ ۲۵۰ ۲۵۰ …, ۲۵۰ ۲۵۰ ۲۵۰]]
>>> print (gray_img.shape)
(۶۴۰, ۶۴۰)
>>> print (img.dtype)
uint8

import numpy as np

import cv2

import matplotlib.pyplot as plt

img = cv2.imread(‘test.jpg’)

gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

plt.imshow(cv2.cvtColor(gray_img, cv2.COLOR_GRAY2RGB))

plt.show()

grayscale

تبدیل به تصویر خاکستری

 

background-subtraction

به دست آوردن تفریق دو تصویر با دستور BackgroundSubtractorMOG در پایتون

تفریق تصویر

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

چندین الگوریتم برای این منظور معرفی شدند. 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) &amp; 0xff
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()
Background Subtraction

Background Subtraction

 

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) &amp; 0xff
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()
Background Subtraction

https://docs.opencv.org.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) &amp; 0xff
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()
 
Background Subtraction

Background Subtraction



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

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

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

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

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

۱۰- هیستوگرام در پردازش تصویر


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)

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


image -processing-python-opencv

نمایش تصویرRGB با Matplotlib و تابع تبدیل ()cvtColor در OpenCv

.

۱- نمایش تصویرRGB با Matplotlib
۱- ۲خواندن و نمایش تصویر فقط با opencv
۱- ۳خواندن و نمایش تصویر فقط با matplotlib
۱- ۴ خواندن تصویر با opencv و نمایش آن توسط matplotlib
۲- تابع تبدیل ()cvtColor در OpenCv

 

 


نمایش تصویرRGB با Matplotlib

 


می دانیم که کتابخانه  matplotlib ، برای کار با نمودارها و ارقام است. اما اگر خواستیم یک تصویر ساده RGB را نمایش دهیم چه؟ آیا می توانیم با matplotlib انجام دهیم؟

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

یک تصویر RGB، که گاهی اوقات به عنوان یک تصویر رنگی واقعی نامیده می شود، به صورت یک آرایه سه بعدی  داده m × n × ۳ ذخیره می شود که کانالهای قرمز، سبز و آبی رنگ را برای هر پیکسل تعریف می کند. رنگ هر پیکسل با ترکیبی از فرمت های فایل های گرافیکی تصاویر RGB، به عنوان تصاویر ۲۴(۸*۳) بیتی ذخیره می شود، حال آنکه هر کدام از کانالهای قرمز، سبز و آبی ۸ بیت هستند.

 

نمایش تصویرRGB توسط Matplotlib

تصویر اصلی

 

خواندن و نمایش تصویر فقط با opencv

کد زیر فقط از opencv برای خواندن و نمایش تصویر استفاده  کرده است. توجه داشته باشید که فرمت رنگ پیش فرض در OpenCV  BGR است (بایت ها معکوس می شوند).

import numpy as np
import cv2
img = cv2.imread('test.png')
cv2.imshow('opencv',img)
cv2.waitKey (0)
cv2.destroyAllWindows ()

خروجی:

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

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

 

خواندن و نمایش تصویر فقط با matplotlib

در کد زیر هم فقط از matplotlib برای خواندن و نمایش تصویر  استفاده شده است.

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
image = mpimg.imread(&amp;quot;img2.png&amp;quot;)
plt.imshow(image)
plt.show()

اولین کاری که ما انجام می دهیم این است که کتابخانه matplotlib را وارد کنیم.

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

 

نمایش تصویر با استفاده از matplotlib با محور دور تصویر

نمایش تصویر با استفاده از matplotlib با محور دور تصویر

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

plt.axis(“off”)
plt.imshow(image)
plt.show()
 
 

خواندن تصویر با opencv و نمایش آن توسط matplotlib

import cv2
import matplotlib.pyplot as plt
image = cv2.imread(&amp;quot;img2.png&amp;quot;)
plt.axis(&amp;quot;off&amp;quot;)
plt.imshow(image)
plt.show()

 

اما نتیجه انتظار نمی رفت تصویر زیر باشد:

خواندن تصویر با opencv و نمایش آن توسط matplotlib

خواندن تصویر با opencv و نمایش آن توسط matplotlib

 

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

پاسخ به عنوان یک نکته در opencv نهفته است.

 

نکته

OpenCV تصاویر RGB را به عنوان آرایه های چند بعدی Numpy معرفی می کند … اما به ترتیب معکوس! به این معنی که تصاویر در واقع در BGR به جای RGB نشان داده شده است!

پس چگونه این مسئله را حل کنیم؟

 

 تصویر را از BGR به RGB   تبدیل   کنیم:


تابع تبدیل ()cvtColor در OpenCv 


این تابع یک تصویر ورودی را از یک فضای رنگی به یکی دیگر تبدیل می کند.  در صورت تغییر به-از فضای رنگ RGB، منظور از کانال ها باید صریح مشخص شود (RGB یا BGR).

cv2.cvtColor(src, code[, dst[, dstCn]]) → dst

پارامتر ها

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

۸-bit unsigned, 16-bit unsigned ( CV_16UC… )

dst : تصویر خروجی که اندازه و عمق آن باید مثل تصویر ورودی باشد.

code : کد تبدیل فضای رنگ

dstCn – تعداد کانال ها در تصویر مقصد؛ اگر پارامتر ۰ باشد، تعداد کانال ها به صورت خودکار از src و کد به دست می آید.

چرا در OpenCV  فضای رنگ BGR  است؟

 توجه داشته باشید که فرمت رنگ پیش فرض در OpenCV اغلب به عنوان RGB نامیده می شود اما در واقع BGR است (بایت ها معکوس می شوند).

  بنابراین بایت اول یک تصویر استاندارد ۲۴ بیتی،  8 بیتی،  آبی ، بایت دوم سبز  و بایت سوم قرمز خواهد بود. بایت های چهارم، پنجم و ششم پیکسل دوم (آبی، سپس سبز، سپس قرمز)، و غیره

محدوده  معمول برای مقادیر کانال R، G و B عبارتند از:

۰ to 255 for CV_8U images

۰ to 65535 for CV_16U images

۰ to 1 for CV_32F images

CV_8U  – یعنی یک پیکسل می تواند مقادیر ۰-۲۵۵ داشته باشد، این محدوده طبیعی برای اکثر فرمت های تصویری و فیلم است.

CV_32F – پیکسل می تواند هر مقدار بین ۰-۱٫۰ داشته باشد، برای برخی از مجموعه محاسبات در داده ها مفید است – اما باید آن را به ۸ بیت برای ذخیره یا نمایش با ضرب کردن هر پیکسل به ۲۵۵ تبدیل کنید.

CV_8U: یک عدد صحیح بدون علامت ۱ بایت (unsigned char).
CV_32S عدد صحیح علامت دار (int).
CV_32F: نقطه شناور ۴ بایت.

 

import numpy as np
import matplotlib.pyplot as plt
import cv2
img = cv2.imread('img2.png')
temp = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(temp)
plt.axis('off')
plt.show()

 

نتیجه اسکریپت ما نشان می دهد که رنگ های تصویر ما درست است.

 



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

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

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

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

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


آموزش قبلی

https://sufra.ir/2017/12/%D9%BE%D8%B1%D8%AF%D8%A7%D8%B2%D8%B4-%D8%AA%D8%B5%D9%88%DB%8C%D8%B1%D8%A8%D8%A7-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86/

 

آموزش بعدی

 

 

Histogram in OpenCv

 هیستوگرام در پردازش تصویر

۱- نمودار هیستوگرام چیست؟
۱-۲- هیستوگرام برای تصاویر رنگی
۱-۳- متعادل سازی هیستوگرام


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

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

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

 

هیستوگرام 

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 تعداد پیکسل.

Histogram

Histogram

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

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

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

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

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

Histogram

تصویر اصلی

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) &amp; 0xFF     
    if k == 27: break             # ESC key to exit 
cv2.destroyAllWindows()

hisgray

image_histogram

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) &amp; 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) &amp; 0xFF     
    if k == 27: break             # ESC key to exit 
cv2.destroyAllWindows()
his-color-image

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


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

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

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

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

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

histogram_equalization

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

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
۲-آموزش نصب pip در پایتون
۳-
کتابخانه های مورد نیاز پردازش تصویر
۴ – خواندن و نمایش فرمت تصویر در پایتون
۵- نمایش تصویرRGB با Matplotlib و تابع تبدیل ()cvtColor در OpenCv

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

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

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

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

۱۰- هیستوگرام در پردازش تصویر


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

آستانه گذاری ساده-تطبیقی -Otsu

۱- آستانه  گذاری ساده
۱-۲- cv2.threshold
۱-۳- آستانه گذاری باینری
۱-۴- آستانه گذاری باینری معکوس
۱-۵- Truncate Thresholding ( type = THRESH_TRUN
۱-۶- Inverted Threshold to Zero
۲- Adaptive Thresholding
۳- Otsu’s Binarization


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

مرسوم ترین خصوصیت تصویر برای  آستانه گذاری، سطح  خاکستری پیکسل است:
اگر T آستانه باشد

g(x,y) = ۰ if f(x,y) < T  و g(x,y) = ۱ if f(x,y) ≥ T

اگر دو تا آستانه داشته باشیم  T1 < T1  :

g(x,y) = ۰ if f(x,y) < T1 OR f(x,y) > T2 and g(x,y) = ۱ if T1 ≤ f(x,y) ≤ T2

Simple Thresholding

https://www.cs.auckland.ac.nz

 

cv2.threshold

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

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

cv2.threshold(src, thresh, maxval, type[, dst]) → retval, dst

پارامترها

src : آرایه ورودی همان تصویر ورودی( تک کاناله(خاکستری )، ۸ بیتی یا ۳۲ بیتی شناور)

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

thresh : مقدار آستانه

maxval : حداکثر مقدار برای استفاده دو نو آستانه گذاری ساده THRESH_BINARY و THRESH_BINARY_INV .

type  : نوع آستانه گذاری

 

OpenCV سبک های مختلف آستانه گذاری ساده  را فراهم می کند و توسط پارامتر چهارم تابع تعیین می شود:

  • cv2.THRESH_BINARY
  • cv2.THRESH_BINARY_INV
  • cv2.THRESH_TRUNC
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZERO_INV
Simple Thresholding

https://docs.opencv.org

 

 

آستانه گذاری باینری

ساده ترین شکل آستانه گذاری ، آستانه گذاری باینری نامیده می شود.

اگر (src (x، y بزرگتر از thresh باشد، مقدار (dst (x، y(تصویر مقصد) به maxValue تنظیم میشود، در غیر اینصورت آن را صفر تنظیم می کند.

ifsrc(x,y) &amp;amp;gt; thresh
dst(x,y) =maxValue
else
dst(x,y)  =0

Simple Thresholding

Simple Thresholding

 

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

 دو خروجی به دست می آید.یکی از آنها retval  است که بعدا توضیح داده خواهد شد.خروجی دوم تصویر آستانه ای است. بنابراین حتما باید از دو متغیر استفاده کنیم. 

Simple Thresholding

https://www.learnopencv.com

کد:

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

img = cv2.imread('threshold.png')
#&amp;amp;lt;strong&amp;amp;gt;thresh&amp;amp;nbsp;&amp;amp;lt;/strong&amp;amp;gt;= 0 و&amp;amp;nbsp;&amp;amp;lt;strong&amp;amp;gt;maxValue&amp;amp;lt;/strong&amp;amp;gt;&amp;amp;nbsp;= 255.
ret,thresh1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY)
#با تغییر آستانه به ۳۵، شدت نور بالاتر از  ۳۵ نمایش داده میشود. 
ret,thresh2 = cv2.threshold(img,35,255,cv2.THRESH_BINARY)
ret,thresh3 = cv2.threshold(img,65,255,cv2.THRESH_BINARY)
#با آستانه ۱۲۷ و بیشترین مقدار ۱۲۵ ، شدت نور بالاتر از ۱۲۷ و با رنگ ۱۲۸ نمایش داده میشود. 
ret,thresh4 = cv2.threshold(img,127,128,cv2.THRESH_BINARY)
ret,thresh5 = cv2.threshold(img,0,128,cv2.THRESH_BINARY)

titles = ['Original Image','THRESH1','THRESH12','THRESH3','THRESH4','THRESH6']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):
 plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
 plt.title(titles[i])
 plt.xticks([]),plt.yticks([])

plt.show()
THRESH_BINARY

THRESH_BINARY

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('threshold.png')
ret,thresh1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY)
# تغییر بیشترین مقدار به ۱۲۸، مقدار بخش آستانه گذاری شده را به ۱۲۸ تنظیم می کند.
ret,thresh2 = cv2.threshold(img,0,128,cv2.THRESH_BINARY)
ret,thresh3 = cv2.threshold(img,0,201,cv2.THRESH_BINARY)
ret,thresh4 = cv2.threshold(img,0,66,cv2.THRESH_BINARY)
ret,thresh5 = cv2.threshold(img,0,33,cv2.THRESH_BINARY)
titles = ['Original Image','THRESH255','THRESH128','THRESH201','THRESH6','THRESH33']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()

آستانه گذاری باینری معکوس

Inverse Binary Thresholding ( type = THRESH_BINARY_INV )
معکوس کردن آستانه گذاری دوتایی (فقط دو مقار سفید و سیاه را داریم) است.

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

if  src(x,y) &amp;gt; thresh
dst(x,y) = 0
else
dst(x,y) =maxValue

کد:

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

img = cv2.imread('threshold.png')
ret,thresh1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,0,128,cv2.THRESH_BINARY_INV)

titles = ['Original Image','THRESH_BINARY','THRESH_BINARY_INV']
images = [img, thresh1, thresh2]
for i in range(3):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])

plt.show()
THRESH_BINARY_INV

“THRESH_BINARY_INV

( Truncate Thresholding ( type = THRESH_TRUN

در این نوع آستانه، پیکسل مقصد به آستانه (thresh) تنظیم می شود اگر مقدار پیکسل منبع بیشتر از آستانه باشد. در غير اين صورت آن را به مقدار پيکسل منبع تنظيم مي کنيم. maxValue نادیده گرفته شده است.

الگوریتم:

if src(x,y) &amp;amp;gt; thresh
dst(x,y) =thresh
else
dst(x,y) =src(x,y)

توجه داشته باشید که تمام مقادیر بالای آستانه (۱۲۷) به ۱۲۷ تنظیم شده و تمام مقادیر کمتر یا برابر ۱۲۷ بدون تغییر هستند.

maxValue نادیده گرفته شده است

کد:

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('threshold.png',0)
ret,thresh1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,0,127,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
titles = ['Original Image','THRESH_BINARY','THRESH_BINARY_INV','THRESH_TRUNC']
images = [img, thresh1, thresh2,thresh3]
for i in range(4):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
Truncate Thresholding

Truncate Thresholding

Truncate Thresholding

Truncate Thresholding

Threshold to Zero ( type = THRESH_TOZERO )

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

الگوریتم:

if src(x,y) &amp;gt; thresh
  dst(x,y) =src(x,y)
else dst(x,y) =&amp;gt;0

کد:

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

img = cv2.imread('threshold.png',0)
ret,thresh1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,0,127,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)

titles = ['Original Image','THRESH_BINARY','THRESH_BINARY_INV','THRESH_TRUNC','THRESH_TOZERO']
images = [img, thresh1, thresh2,thresh3,thresh4]
for i in range(5):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])

plt.show()

THRESH_TOZERO

THRESH_TOZERO

Inverted Threshold to Zero ( type = THRESH_TOZERO_INV)

در این نوع آستانه، اگر مقدار پیکسل منبع بیشتر از آستانه باشد، مقدار پیکسل مقصد به مقدار صفر تنظیم می شود . در غير اين صورت آن را به مقدار پيکسل منبع تنظيم مي کنيم. maxValue نادیده گرفته شده است.

الگوریتم:

if src(x,y) &amp;gt; thresh
dst(x,y) =0
else
dst(x,y) =src(x,y)

کد:

import cv2
 import numpy as np
 from matplotlib import pyplot as plt
img = cv2.imread('threshold.png',0)
 ret,thresh1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY)
 ret,thresh2 = cv2.threshold(img,0,127,cv2.THRESH_BINARY_INV)
 ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
 ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
 ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)titles
 = ['Original Image','THRESH_BINARY','THRESH_BINARY_INV','THRESH_TRUNC','THRESH_TOZERO','THRESH_TOZERO_INV']
 images = [img, thresh1, thresh2,thresh3,thresh4,thresh5]
 for i in range(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
 plt.xticks([]),plt.yticks([])plt.show()
THRESH_TOZERO_INV

THRESH_TOZERO_INV

 

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)

 

Adaptive Thresholding

Adaptive Thresholding

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

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 ()

 

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

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

Adaptive Thresholding

Adaptive Thresholding

Adaptive Thresholding

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

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

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

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

Adaptive Thresholding

Adaptive Thresholding

Adaptive Thresholding

Adaptive Thresholding


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

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

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

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

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

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

Otsu’s Binarization

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

Otsu’s Binarization

Otsu’s Binarization

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 (تصویری که هیستوگرام آن دارای دو قله میباشد)، تقریبا در وسط قله ها می توان آستانه بهینه را انتخاب کرد. 

Otsu’s Binarization

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

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

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

 

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

Otsu’s Binarization

تصویر اصلی

Otsu’s Binarization

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

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



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

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

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

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

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

۱۰- هیستوگرام در پردازش تصویر


 

Image Segmentation

آستانه گذاری درOpenCV

۱- Image Segmentation
۱- آستانه گداری(Threshold) تصویر چیست؟


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

هدف پردازش تصویر دیجیتال، استخراج اطلاعات مفید(آبجکت، شی، ۲۵۵، ۱، روشن) از تصاویر، بدون کمک انسان است.

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

 

 

خروجی بخشبندی

 

۱) پیکسلهای لبه یا مرز یک بخش. کاربرد:  گوشه ها یا حالت  ناحیه ی مد نظر  را مشخص میکند.

۲) تمام پیکسلهای درون یک بخش. کاربرد: ویژگیهای درونی بخش های تصویر مثل بافت، رنگ و … را مشخص میکند.

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

 

تکنیکهای بخشبندی

۱)  contextual (بخش بندی بر اساس لبه ها)

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

Contexuall

۲) non-contextual (بخش بندی بر اساس نواحی)

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

non

کاربرد بخشبندی

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

آستانه گداری(Threshold) تصویر چیست؟

آستانه‌گذاری  مناسب‌ترین و ساده ترین تکنیک بخش بندی non-contextual است.
با اعمال آستانه‌گذاری بر روی تصویر در مقیاس خاکستری، تصویری باینری(۰و۱) بدست می‌آید که تصویر به دو بخش کاملا جدا از هم تقسیم میشود.یکی از آنها حاوی پیکسل هایی با مقادیر داده ورودی کوچکتر از آستانه و دیگری مربوط به مقادیر ورودی است که برابر آستانه یا بیشتراز آن هستند. مناطق اول و دوم معمولا به ترتیب با برچسب صفر (۰) و غیر صفر (۱) برچسب گذاری می شوند. آستانه گذاری ، ممکن است دارای چند آستانه باشد که تصویر را به چند بخش مجزا تقسیم میکنند.

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

به عبارت دیگر آستانه گذاری شامل تقسیم یک تصویر به دو منطقه است: یک منطقه آبجکت و یک منطقه پس زمینه.
threshold e

تصویر زیر را با دقت مشاهده کنید:

threshold

https://www.learnopencv.com

چند عدد می بینید؟
اکثر شما اعداد زیر را می بینید:
۳۲ (آه، بله، به دقت نگاه کنید)، ۶۴، ۱۰۰، ۱۲۸، ۱۸۰، ۲۰۰ و ۲۵۵٫ اما در تصویر، اعداد بیشتری وجود دارد که به چشم نمیاد.

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

در حقیقت تمام اعداد در تصویر اصلی یک مقدار خاکستری  برابر با عدد دارند. بنابراین ۲۵۵ روشنترین و ۵ تاریک ترین است.

 خواندن اعداد در تصویر آستانه گذاری شده  آسان تر از خواندن اعداد در تصویر اصلی است. جای تعجب نیست که یک الگوریتم  تصویر آستانه گذاری شده، بسیار ساده تر از تصویر اصلی،  پردازش می کند.
تمام الگوریتم های آستانه گذاری، یک تصویر منبع (src) و مقدار آستانه (thresh) به عنوان ورودی میگیرند، و با مقایسه مقادیر پیکسل در پیکسل  تصویر منبع (x، y) با آستانه،  یک تصویر خروجی (dst) تولید می کند. اگر src (x، y)> thresh باشد، سپس (dst (x، y یک مقدار را تعیین می کند. در غیر این صورت، (dst (x، y مقدار دیگری را ایجادمی کند.

سه روش آستانه ‘گذاری داریم که در قسمتهای بعدی توضیح داده خواهند شد:
+ Simple thresholding
+ Adaptive thresholding
+ Otsu’s thresholding

 



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

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

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

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

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

 


 

image -processing-python-opencv

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

۱- تغییر فضاهای رنگ- opencv
۲- HSV
۲-۱ Hue
۲-۳ Value
۲-۴ Saturation or intensity
۲-۵ HSV چه کاربردی دارد؟
۲-۵ استخراج سه شی رنگی از تصویر
۲-۵ برای پیدا کردن مقادیر HSV چکار باید کرد؟
۳- Grayscale


تغییر فضاهای رنگ

 

در این آموزش،  نحوه ی  تبدیل تصاویر از یک فضای رنگی به دیگری را  یاد خواهیم گرفت. مانند: BGR \leftrightarrowGray, BGR \leftrightarrow HSV. علاوه بر این، یک برنامه ایجاد می کنیم که ۳ شیء رنگی را از یک تصویر استخراج کند، و در ادامه به تصاویر خاکستری می پردازیم. در OpenCV، بیش از ۱۵۰ روش تبدیل فضای رنگ وجود دارد. اما تنها دو مورد که بیشتر مورد استفاده قرار می گیرند، به BGR ↔ Gray و BGR ↔ HSV را توضیح می دهیم .


برای تبدیل رنگ، از تابع (cv2.cvtColor (input_image، flag استفاده می کنیم که در آن پرچم، نوع تبدیل را تعیین می کند.

برای تبدیل  BGR →Gray،   از پرچم cv2.COLOR_BGR2GRAY و برای BGR → HSV، از پرچم cv2.COLOR_BGR2HSV استفاده می کنیم. .
برای دریافت پرچم های دیگر، فقط دستورات زیر را در ترمینال پایتون خود اجرا کنید:

import cv2
flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
print flags

 (HSV)

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

Hue


نام رنگ (زرد، سبز، صورتی و..) . 

Value

 

روشنایی یا تیرگی رنگ (خاکستری)



Saturation or intensity

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

 

نکته

در فضای رنگ HSV، محدوده رنگ [۰،۱۷۹]، محدوده اشباع [۰،۲۵۵] و محدوده مقدار [۰،۲۵۵] است. نرم افزار های مختلف از مقیاس های مختلف استفاده می کنند. بنابراین اگر مقادیر OpenCV را با آنها مقایسه کنید، باید این محدوده ها را نرمال کنید.

مدل رنگ HSV چه کاربردی دارد؟

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

در HSV، رنگ آمیزی ساده تر از BGR رنگی است. 

 

 

hsv

 

hsv
hsv
hsv

HSV

 

استخراج سه شی رنگی از تصویر

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

  1. برنامه،  تصویر را بگیرد
  2. تبدیل از فضای رنگ BGR به HSV انجام دهد.

 

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

در حال حاضر تنها ۳ شیء آبی و سبز و قرمز را استخراج می کنیم، می توانیم هر آنچه را که می خواهیم انجام دهیم.
کد:

 

import cv2
import numpy as np
img = cv2.imread('bgrtohsv.png')
#تبدیل فضای رنگ bgr to hsv
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV )

lower_blue = np.array([110,50,50])
upper_blue = np.array([120,255,255])

lower_green = np.array([50,50,50])
upper_green = np.array([60,255,255])

lower_red = np.array([0,50,50])
upper_red = np.array([0,255,255])
#آستانه گیری(cv2.inRange())
maskb = cv2.inRange(hsv, lower_blue, upper_blue)
maskg = cv2.inRange(hsv, lower_green, upper_green)
maskr = cv2.inRange(hsv, lower_red, upper_red)
# and تصویر اصلی با ماسک
#میشود (cv2.bitwise_and())
resb = cv2.bitwise_and(img,img, mask= maskb)
resg = cv2.bitwise_and(img,img, mask= maskg)
resr = cv2.bitwise_and(img,img, mask= maskr)

cv2.imshow('original image',img)
cv2.imshow('maskb',maskb)
cv2.imshow('maskg',maskg)
cv2.imshow('maskr',maskr)

cv2.imshow('resb',resb)
cv2.imshow('resg',resg)
cv2.imshow('resr',resr)

cv2.waitKey()
cv2.destroyAllWindows()

rgb-hsv

استخراج سه شی رنگی از تصویر

 

نکته

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

 

برای پیدا کردن مقادیر HSV چکار باید کرد؟

بسیار ساده است و شما می توانید از همان تابع ()cv2.cvtColor  استفاده کنید.

برای مثال، برای پیدا کردن مقدار HSV سبز، دستورات زیر را در ترمینال پایتون امتحان کنید:

green = np.uint8([[[0,255,0 ]]])
hsv_green = cv2.cvtColor(green,cv2.COLOR_BGR2HSV)
print hsv_green
[[[ ۶۰ ۲۵۵ ۲۵۵]]]

اکنون شما می توانید [H-10، ۱۰۰،۱۰۰] و [H + 10، ۲۵۵، ۲۵۵] را به ترتیب پایین تر و بالاتر محدوده رنگ  قرار دهید.

به غیر از این روش، می توانید از هر ابزار ویرایش عکس مانند GIMP یا هر مبدل آنلاین برای پیدا کردن این ارزش ها استفاده کنید.

اما فراموش نکنید که محدوده های HSV را تنظیم کنید.

 

تصاویر Grayscale(خاکستری)

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

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

Grayscale

http://hamamatsu.magnet.fsu.edu

تصاویر خاکستری فقط دارای یک کانال رنگی(۸بیتی) در مقیاس ۰ تا ۲۵۵ هستند که نشان دهنده روشنایی آن پیکسل است، ۰ کاملا تاریک (سیاه) و ۲۵۵ کاملا روشن (سفید) است.

Grayscale

Grayscale

 

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

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

مثلا به رنگ سبز دقت کنید، فقط قسمتی که رنگ سبز داریم سفید وبقیه قسمت ها سیاه است. کانال سبز  یک کانال ۸ بیتی که به صورت   [0,255,0]:rgb مقدار دهی می شود و نشان دهنده ی این است که هر چه شدت نور به سمت ۲۵۵ باشد رنگ سبز بیشتر و هر چه به سمت ۰ باشد رنگ سبز کمتری داریم و در مورد کانال های دیگر هم همین استدلال را میشه کرد.

Grayscale

Grayscale

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

import numpy as np
import cv2
import matplotlib.pyplot as pltimg = cv2.imread('test.jpg')
gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
#تصویر خاکستری به عنوان آراه ای دوبعدیprint(gray_img)
[[۲۵۰ ۲۵۰ ۲۵۰ ..., ۲۵۰ ۲۵۰ ۲۵۰]
[۲۵۰ ۲۵۰ ۲۵۰ ..., ۲۵۰ ۲۵۰ ۲۵۰]
[۲۵۰ ۲۵۰ ۲۵۰ ..., ۲۵۰ ۲۵۰ ۲۵۰]
...,
[۲۵۰ ۲۵۰ ۲۵۰ ..., ۲۵۰ ۲۵۰ ۲۵۰]
[۲۵۰ ۲۵۰ ۲۵۰ ..., ۲۵۰ ۲۵۰ ۲۵۰]
[۲۵۰ ۲۵۰ ۲۵۰ ..., ۲۵۰ ۲۵۰ ۲۵۰]]
print (gray_img.shape)&amp;amp;lt;/span&amp;amp;gt;
(۶۴۰, ۶۴۰)
print (img.dtype)
uint8

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

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('test.jpg')
gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
plt.imshow(cv2.cvtColor(gray_img, cv2.COLOR_GRAY2RGB))
plt.show()
grayscale

تبدیل به تصویر خاکستری

 



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

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