اعمال مقدماتی بر روی عکس در OpenCV

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

[اگر OpenCV رو نصب ندارید می‌تونید از این آموزش اون رو روی ubuntu نصب کنید.]

خواندن، نمایش، تغییر رنگ و ذخیره‌ی عکس در OpenCV:

در OpenCV جهت خواندن عکس از دستور imread جهت دخیره ی تصویر در حافظه از imwriteو جهت نمایش آن از دستور imshow استفاده می‌کنیم:

دستورهای بالا رو در عمل ببینیم تا بیشتر توضیح بدم:

#فرا خواندن کتابخانه‌ی Opencv
import cv2

#بارگذاری یک عکس از آدرسی در حافظه
image = cv2.imread("mrFox.jpg")

#بررسی می‌کنیم که آیا عکس به شکل صحیح بارگذاری شده است یا نه
if image is None:
        print ("Coud not open or find the image")

#با این دستور عکس رنگی را به سیاه و سفید تبدیل می‌کنیم
grayImage = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)

#ذخیره نتیجه تبدیل عکس رنگی به سیاه و سفید
cv2.imwrite("grayImage.jpg",grayImage)

#ایجاد پنجره برای نمایش عکس‌ها
cv2.namedWindow("Image",cv2.WINDOW_AUTOSIZE)
cv2.namedWindow("Gray Image",cv2.WINDOW_NORMAL)

#نمایش عکس‌ها
cv2.imshow("Image",image)
cv2.imshow("Gray Image",grayImage)

#صبر می‌کنیم تا یک کلید فشرده شود
cv2.waitKey(0)

imread دوتا ورودی از ما می‌گیره، ورودی اول اسم و آدرس عکس ذخیره شده در حافظه و ورودی دوم اون شامل یک فلک است که color type عکس رو مشخص می‌کنه.

cv2.imread(filename[, flags])

Parameters:

  • filename – Name of file to be loaded.
  • flags

    Flags specifying the color type of a loaded image:

    • CV_LOAD_IMAGE_ANYDEPTH – If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
    • CV_LOAD_IMAGE_COLOR – If set, always convert image to the color one
    • CV_LOAD_IMAGE_GRAYSCALE – If set, always convert image to the grayscale one
    • >0 Return a 3-channel color image.

      Note

      In the current implementation the alpha channel, if any, is stripped from the output image. Use negative value if you need the alpha channel.

    • =0 Return a grayscale image.
    • <0 Return the loaded image as is (with alpha channel).

 

قبلا هم گفتم [این پست] که ما می‌توینم بجای سه Falg بالا از 1، 0 و -1 استفاده کنیم و همچنین مقدار پیش‌فرض ورودی دوم CV_LOAD_IMAGE_COLOR است.

دقت کنید  اگر عکسی که آدرس اون رو به دستور imread می‌دهیم موجود نباشه ما خطایی نمی‌گیریم (در عمل یک عکس خالی [None] ایجاد میشه)، برای همین بهتره چک کنیم که آیا عکس به درستی بارگذاری شده یا نه [خط ۸ و ۹.]

خط ۱۲: با استفاده از دستور cvtColor می‌توانیم رنگ عکس رو تغییر بدهیم، توضیح کامل این دستور در این لینک.

در خط ۱۵ ما عکس خاکستری تولید شده از روی عکس اصلی رو با دستور imwrite ذخیره کرده‌ایم.

 

به خط ۱۸ توجه کنید، برای نمایش تصاویر ابتدا به وسیله‌ی دستورcv2.namedWindow یک پنجره ایجاد می‌کتیم، این دستور جدا از اسم پنجره سه پارامتر دیگه هم می‌گیره:

cv2.namedWindow(winname[, flags])

Parameters:.

  • name – Name of the window in the window caption that may be used as a window identifier.
  • flags –Flags of the window. The supported flags are:
    • WINDOW_NORMAL If this is set, the user can resize the window (no constraint).
    • WINDOW_AUTOSIZE If this is set, the window size is automatically adjusted to fit the displayed image, and you cannot change the window size manually.
    • WINDOW_OPENGL If this is set, the window will be created with OpenGL support

این سه پارامتر نوع و اندازه‌ی پنجره رو مشخص می‌کنه. [من در اوبونتو یک باگ دارم و اون اینکه سایز پنجره هنگام استفاده از دستور WINDOW_AUTOSIZE به تناسب صفحه‌ی نمایشم تغییر نمی‌کنه.]

سپس در خط ۲۲ تصویرمون رو نمایش می‌دهیم به این شکل که ابتدا اسم پنجره‌ای که می‌خواهیم تصویر در اون نمایش داده بشه رو می‌گیم (همون اسمی که در خط ۱۸ و ۱۹ ایجاد کردیم) و سپس اسم متغیر عکسی که می‌خواهیم نمایش داده بشه رو وارد می‌کنیم.

در مورد دستور خط آخر [cv2.waitKey(0)]، این دستور پنجره‌ها تا زمانی که یک کلید فشرده بشه باز نگه می‌داره، اگر این دستور رو وارد نکنیم عملا نتیجه‌ی کار رو نمی‌بینم (چون پنجره‌ها بلافاصله بسته می‌شوند.)

برش و تغییر اندازه‌ی عکس در OpenCV:

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

# کتابخانه‌ی OpenCV رو فرا می‌خونیم
import cv2

# مانند قبل تصویر رو بارگذاری کرده و بررسی می‌کینم آیابه درستی خوانده شده یا نه
originalImage = cv2.imread("mrFox.jpg")
if originalImage is None:
 print("Oh! we have problem in reading image!")

# تصویر رو با نسبت‌های داده شده .۲ و.۱ کوچک می‌کنیم
scaleDown = cv2.resize(originalImage, None, fx=0.1, fy=0.2, interpolation=cv2.INTER_LINEAR)

# تصویر را به نسبت ۲ و ۲ بزرگ می‌کنیم
scaleUp = cv2.resize(originalImage, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)

# از ۲۵۰ تا ۳۰۰ محورایکس و ۱۰۰ تا ۲۰۰ محور ایگرگ را از تصویر اصلی جدا کرده و در متغیر جدید ذخیره می‌کنیم
crop = originalImage[250:300, 100:200]

# مثل قبل تصاویررا نمایش می‌دهیم
cv2.imshow("Original", originalImage)
cv2.imshow("Scaled Down", scaleDown)
cv2.imshow("Scaled Up", scaleUp)
cv2.imshow("Cropped Image", crop)

cv2.waitKey(0)

ما در برنامه‌ی بالا اومدیم و نسبت طول و عرض عکس رو با استفاده از ضرایب fx و fy تغییر دادم، اما اگر بخواهیم تصویر رو به سایز دقیقی مثل ۶۴۰*۴۸۰ تغییر اندازه بدهیم باید به شکل زیر عمل کنیم:

resized = cv2.resize(originalImage,(640,480))

این که اومدیم و سایز عکس رو به شکل فله‌ای با دستور بالا تغییر دادیم خیلی جالب نیست، نه؟ بهتره به شکل زیر کار کنیم تا ابعاد تصویر بهم نریزه:

# کتابخانه‌ی OpenCV رو فرا می‌خونیم
import cv2

# مانند قبل تصویر رو بارگذاری کرده و بررسی می‌کینم آیابه درستی خوانده شده یا نه
image = cv2.imread("mrFox.jpg")
if image is None:
    print("Oh! we have problem in reading image!")

# برای این که نسبت‌های عکس بهم نریزه باید مقادیر طول و عرض عکس رو ذخیره کنیم و
# و به نسبت اون‌ها عکس رو تغییر ابعاد بدهیم
xRatio = 480.0
r = xRatio / image.shape[1]
dim = (int(xRatio), int(image.shape[0] * r))

# تغییر ابعاد عکس
resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
cv2.imshow("Original Image", image)
cv2.imshow("resized Image", resized)
# چاپ ابعاد اصلی و ابعاد تغییر یافته
print("Original image size: ", image.shape)
print("Resized image size: ", dim)
cv2.waitKey(0)

به کاربرد .shape دقت کنید. قبلا در این پست در موردش توضیح دادم.

اطلاعات کامل دستور resize  رو هم اینجا میارم:

cv2.Resize(src, dst, interpolation=CV_INTER_LINEAR)

Parameters:

  • src – input image.
  • dst – output image; it has the size dsize (when it is non-zero) or the size computed from src.size(), fx, and fy; the type of dst is the same as of src.
  • dsize –output image size; if it equals zero, it is computed as:

    \texttt{dsize = Size(round(fx*src.cols), round(fy*src.rows))}

    Either dsize or both fx and fy must be non-zero.

  • fx –scale factor along the horizontal axis; when it equals 0, it is computed as

    \texttt{(double)dsize.width/src.cols}

  • fy –scale factor along the vertical axis; when it equals 0, it is computed as

    \texttt{(double)dsize.height/src.rows}

  • interpolation

    interpolation method:

    • INTER_NEAREST – a nearest-neighbor interpolation
    • INTER_LINEAR – a bilinear interpolation (used by default)
    • INTER_AREA – resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
    • INTER_CUBIC – a bicubic interpolation over 4×4 pixel neighborhood
    • INTER_LANCZOS4 – a Lanczos interpolation over 8×8 pixel neighborhood

اگر دقت کنید در برنامه‌ی بالا ما تصاویر رو مستقیم نمایش دادیم و مثل قبل نبود که ابتدا یک پنجره رو ایجاد کنیم و سپس تصویر رو نمایش بدیم، خوب این هم یک جورشه:-) [وقت‌هایی از این روش نمایش تصویر استفاده می‌کنیم که نمی‌خوایم روی سایز پنجره تغییری ایجاد کنیم، منظورم همون سه‌تا پارامتر دستور  cv2.namedWindow است.]

 

چرخش عکس در OpenCV:

با OpenCV می‌توان عکس رو از هر نقطه‌ای (هر مرکزی) و با هر زاویه‌‌ی چرخش دلخواهی بچرخونیم.

در OpenCV چرخش‌ها به شکل یک ماتریس 2×3 بیان می‌شن به این علت که چرخش عضوی از کلاسی از تبدیلات به اسم Affine Transform است (بعدا بیشتر در موردش صحبت می‌کنیم) بیاید اول شکل ریاضی کار رو ببینیم:

rotMat = getRotationMatrix2D(center, angle, scale)

getRotationMatrix2D returns the following matrix :

Where,
α is given by scale * cos (angle), β is given by scale * sin (angle)

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

# کتابخانه‌ی OpenCV رو فرا می‌خونیم
import cv2

# مانند قبل تصویر رو بارگذاری کرده و بررسی می‌کینم آیابه درستی خوانده شده یا نه
image = cv2.imread("hmrFox.jpg")
if image is None:
    print("Oh! we have problem in reading image!")

# طول و عرض تصویر رو استخراج کرده و با استفاده از اون مرکز عکس رو پیدا می‌کنیم
(h, w) = image.shape[:2]
center = (w / 2, h / 2)
rotationAngle = 180
scaleFactor = 1.0
# عکس رو 180 درجه می‌چرخونیم
rotationMatrix = cv2.getRotationMatrix2D(center, rotationAngle, scaleFactor)
rotated = cv2.warpAffine(image, rotationMatrix, (w, h))
cv2.imshow("rotated 180 deg", rotated)

# عکس رو +45 درجه می‌چرخونیم
rotationMatrix = cv2.getRotationMatrix2D(center, 45, scaleFactor)
rotated = cv2.warpAffine(image, rotationMatrix, (w, h))
cv2.imshow("rotated +45 deg", rotated)

# عکس رو -45 درجه می‌چرخونیم
rotationMatrix = cv2.getRotationMatrix2D(center, -45, scaleFactor)
rotated = cv2.warpAffine(image, rotationMatrix, (w, h))
cv2.imshow("rotated -45 deg", rotated)

# نمابش عکس اصلی
cv2.imshow("Original Image", image)

# ماتریس rotationMatrix رو نمایش می‌دهیم
print(rotationMatrix)

# صبر می‌کنیم تا کاربر کلیدی را فشار دهد
cv2.waitKey(0)

ذخیره‌ی عکس با کیفیت دلخواه:

اول بیایم و تابع ذخیره عکس رو با جزئیات ببینیم:

cv2.imwrite(filename, img[, params])

Parameters:

  • filename – Name of the file.
  • image – Image to be saved.
  • params –Format-specific save parameters encoded as pairs paramId_1, paramValue_1, paramId_2, paramValue_2, ... . The following parameters are currently supported:
    • For JPEG, it can be a quality ( CV_IMWRITE_JPEG_QUALITY ) from 0 to 100 (the higher is the better). Default value is 95.
    • For PNG, it can be the compression level ( CV_IMWRITE_PNG_COMPRESSION ) from 0 to 9. A higher value means a smaller size and longer compression time. Default value is 3.
    • For PPM, PGM, or PBM, it can be a binary format flag ( CV_IMWRITE_PXM_BINARY ), 0 or 1. Default value is 1.

پس ما می‌تونیم کیفیت دلخواه ذخیره‌ی عکسمون بسته به فرمت فشرده‌سازی اون داشته باشیم. یک مثال با هم ببینیم:

# فراخوانی کتابخانه‌های مورد نیاز
import cv2

# بازگگذاری عکس
image = cv2.imread('hmrFox.jpg')

# بررسی معتبر بودن عکس ورودی
if image is None:
    print("Error in readig image")
    exit()

# تبدیل عکس رنگی به خاکستری
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)

# ایجاد پنجره جهت ذخیره‌ی نمایش عکس‌ها
cv2.namedWindow('Image', cv2.WINDOW_AUTOSIZE)
cv2.namedWindow('Gray Image', cv2.WINDOW_AUTOSIZE)

key = 0
# حلقه‌ی بینهایت تا زمانی که کلید q فشرده شود
while key != ord('q'):

# نمایش عکس‌ها
    cv2.imshow('Image',image)
    cv2.imshow('Gray Image', gray)
    key = cv2.waitKey(0) & 0xFF

# ذخیره‌ی عکس خاکستری با کیفیت ۵
cv2.imwrite('Gray.jpg',gray, [cv2.IMWRITE_JPEG_QUALITY,10])

# بستن تمام پنجره‌های باز
cv2.destroyAllWindows()

فکر نکنم نیاز به توضیح خاصی داشته باشیم.

 


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

نویسنده: محمد حسین سالاری

موارد مشابه

۳ دیدگاه

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *