بایگانی برچسب برای: vnhca jw

برنامه نویسی Parallel در سی شارپ :: متوقف کردن Task ها در سی شارپ – کلاس CancellationToken

زمانی که عملیاتی را به عنوان یک Task اجرا می کنیم، ممکن است بخواهیم آن Task را در حین اجرا متوقف کنیم، برای مثال، Task ای داریم که در حال پردازش 1000 فایل است و کاربر باید این امکان را داشته باشد که Task در حال اجرا را متوقف کند. عملیات متوقف کردن Task ها هم برای متدهای کلاس Parallel امکان پذیر است و هم کلاس Task. برای اینکار می بایست از کلاس CancellationToken استفاده کنیم. برای مثال Task زیر را در نظر بگیرید که حاصل میانگین جمع اعداد 1 تا 100 را محاسبه می کند:

Task < int > averageTask = new Task < int > (() =>
{
    Console.WriteLine("Calculating average...");
    Console.WriteLine("Press Ctrl+C to cancel...");
    var sum = 0;
    for (int counter = 1; counter < = 100; counter++)
    {
        sum += counter;
        Thread.Sleep(100);
    }
    Console.WriteLine("All done.");
    return sum/100;
});
averageTask.Start();
Console.WriteLine(averageTask.Result);

قبلاً با این کد آشنا شدیم، اما کاری که در این قسمت می خواهیم انجام دهیم اضافه کردن قابلیتی است که کاربر بتواند با فشردن کلید های Ctrl+C عملیات را متوقف کند. برای اینکار ابتدا شئ ای از نوع کلاس CancellationTokenSource که در فضای نام System.Threading قرار دارد، در کلاس Program به صورت زیر تعریف می کنیم:

Task < int > averageTask = new Task < int > (() = >
{
    Console.WriteLine("Calculating average...");
    Console.WriteLine("Press q to cancel...");
    var sum = 0;
    for (int counter = 1; counter < = 100; counter++)
    {
        sum += counter;
        Thread.Sleep(100);
    }
    Console.WriteLine("All done.");
    return sum/100;
}, source.Token);

شئ source که در کلاس Program ایجاد کردیم متدی دارد با نام Cancel که این متد را زمانی که قصد داریم Task متوقف شود باید فراخوانی کنیم. فراخوانی این متد باید زمانی انجام شود که کاربر کلید های Ctrl+C را فشار داده است. در محیط Console، زمانی که کاربر کلید های Ctrl+C را فشار می دهد، event ای با نام CancelPressKey در کلاس Console فراخوانی می شود، پس باید این از این event برای فراخوانی متد Cancel به صورت زیر استفاده کنیم:

Console.CancelKeyPress += (sender, eventArgs) = >
{
    source.Cancel();
    eventArgs.Cancel = true;
};

به خط دوم داخل event دقت کنید، زمانی که کلید های Ctrl+C فشرده می شوند، به صورت پیش فرض کل برنامه Console متوقف می شود، برای جلوگیری از این کار مقدار خصوصیت Cancel را در شئ eventArgs به مقدار true ست می کنیم، یعنی عملیات متوقف کردن محیط کنسول به صورت دستی توسط ما انجام شده و خود سیستم نیاز به انجام کاری در این باره ندارد.

بعد از Subscribe کردن event بالا، باید به برنامه بگوییم تا زمانی که task به اتمام نرسیده یا کاربر کلید های Ctrl+C را فشار نداده نباید از برنامه خارج شویم، به همین خاطر یک حلقه while به صورت زیر ایجاد می کنیم:

while (!averageTask.IsCompleted &amp;&amp; !source.IsCancellationRequested)
{                                                                                                
}

با خصوصیت IsCompleted در کلاس Task قبلاً آشنا شدیم، اما خصوصیت IsCancellationRequested در شئ source زمانی مقدارش true می شود که متد Cancel فراخوانی شود، پس تا زمانی که عملیات Task به اتمام نرسیده و زمانی که کاربر کلید های Ctrl+C را فشار نداده برنامه در حلقه while منتظر می ماند.

در ادامه باید Task ایجاد شده را به صورتی تغییر دهیم که داخل حلقه for بررسی شود که متد Cancel فراخوانی شده است یا خیر، اگر فراخوانی شده بود باید از Task خارج شویم، برای این کار نیز از خصوصیت IsCancellationRequested در شئ source استفاده می کنیم، Task ایجاد شده را به صورت زیر تغییر می دهیم:

Task < int > averageTask = new Task < int > (() = >
{
    Console.WriteLine("Calculating average...");
    Console.WriteLine("Press Ctrl+C to cancel...");
    var sum = 0;
    for (int counter = 1; counter < = 100; counter++)
    {
        if (source.IsCancellationRequested)
        {
            Console.WriteLine("Operation terminated!");
            return 0;
        }
        sum += counter;
        Thread.Sleep(100);
    }
    Console.WriteLine("All done.");
    return sum/100;
}, source.Token);

همانطور که مشاهده می کنید داخل حلقه for گفتیم که اگر IsCancellationRequested برابر true بود پیغامی را نمایش بده و مقدار 0 را برگردان. کد نهایی ما به صورت زیر می باشد:

class Program
{
    private static CancellationTokenSource source = new CancellationTokenSource();
    static void Main(string[] args)
    {
        Task < int > averageTask = new Task < int >(() = >
        {
            Console.WriteLine("Calculating average...");
            Console.WriteLine("Press Ctrl+C to cancel...");
            var sum = 0;
            for (int counter = 1; counter <= 100; counter++) { if (source.IsCancellationRequested) { Console.WriteLine("Operation terminated!"); return 0; } sum += counter; Thread.Sleep(100); } Console.WriteLine("All done."); return sum/100; }, source.Token); averageTask.Start(); Console.CancelKeyPress += (sender, eventArgs) = >
        {
            source.Cancel();
            eventArgs.Cancel = true;
        };
        while (!averageTask.IsCompleted && !source.IsCancellationRequested)
        {                                                                                                
        }
 
        Console.WriteLine(averageTask.Result);
    }
}

در صورتی که برنامه بالا را اجرا کرده و کلید های Ctrl+C را فشار دهیم خروجی زیر برای ما نمایش داده می شود:

Calculating average...
Press Ctrl+C to cancel...
Operation terminated!
0
Press any key to continue . . .

استفاده از CancellationToken در کلاس Parallel

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

var jpegFiles = System.IO.Directory.GetFiles("D:\\Images", "*.jpg");
 
Parallel.ForEach(jpegFiles, file = >
{
    var fileInfo = new FileInfo(file);
    // process file
});

برای متوقف کردن عملیات پردازش فایل ها، ابتدا شئ ای از نوع CancellationTokenSource مانند مثال قبل ایجاد می کنیم:

private static CancellationTokenSource source = new CancellationTokenSource();

در قدم بعدی کلاسی از نوع ParallelOptions به صورت زیر تعریف کرده، خصوصیت CancellationToken را برابر خصوصیت Token در شئ source قرار داده و این کلاس را به عنوان پارامتر ورودی به متد ForEach به صورت زیر ارسال می کنیم:

ParallelOptions options = new ParallelOptions();
options.CancellationToken = source.Token;
 
try
{
    Parallel.ForEach(jpegFiles,options, file = >
    {
        options.CancellationToken.ThrowIfCancellationRequested();                                                
        var fileInfo = new FileInfo(file);
        // process file
    });
}
catch (OperationCanceledException ex)
{
    Console.WriteLine(ex);
}

دقت کنید در قسمت ForEach متدی با نام ThrowIfCancellationRequested فراخوانی شده است، در حقیقت این متد بعد از فراخوانی بررسی می کند که آیا متد Cancel برای شئ source فراخوانی شده است یا خیر، اگر فراخوانی شده بود خطایی از نوع OperationCanceledException ایجاد می شود که در خارج از بدنه ForEach کلاس Parallel، بوسیله ساختار try..catch این خطا مدیریت شده است. دقت کنید که روند مدیریت Cancel کردن در کلاس Parallel با کلاس Task متفاوت است و دلیل این موضوع نوع برخورد برنامه با این کلاس ها است. در قسمت بعدی با مبحث Parallel LINQ آشنا خواهیم شد.

منبع



قسمت اول آموزش-برنامه نویسی Asynchronous – آشنایی با Process ها، Thread ها و AppDomain ها

قسمت دوم آموزش- آشنایی با ماهیت Asynchronous در Delegate ها

قسمت سوم آموزش-آشنایی با فضای نام System.Threading و کلاس Thread

قسمت چهارم آموزش- آشنایی با Thread های Foreground و Background در دات نت

قسمت پنجم آموزش- آشنایی با مشکل Concurrency در برنامه های Multi-Threaded و راهکار های رفع این مشکل

قسمت ششم آموزش- آشنایی با کلاس Timer در زبان سی شارپ

قسمت هفتم آموزش-آشنایی با CLR ThreadPool در دات نت

قسمت هشتم آموزش- مقدمه ای بر Task Parallel Library و کلاس Parallel در دات نت

قسمت نهم آموزش- برنامه نویسی Parallel:آشنایی با کلاس Task در سی شارپ

قسمت دهم آموزش-برنامه نویسی Parallel در سی شارپ :: متوقف کردن Task ها در سی شارپ – کلاس CancellationToken

قسمت یازدهم آموزش- برنامه نویسی Parallel در سی شارپ :: کوئری های Parallel در LINQ

قسمت دوازدهم آموزش- آشنایی با کلمات کلیدی async و await در زبان سی شارپ

قسمت سیزدهم آموزش- استفاده از متد WhenAll برای اجرای چندین Task به صورت همزمان در سی شارپ

 OSD (on screen Display) Menu Setup

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

Menu Setup

DWDR

تصاویر ویدئویی واضح تر و با جزئیات بیشتر. DWDR نقاط سایه ای سیاهی که در تصویر بوجود می آید را از بین می برد این قابلیت در محیط هایی که هم نقاط تیره و هم نقاط روشن دارد بسیار کاربردی است .

DWDR

SMART IR

این ویژگی از بین برنده ی نوردهی بالای چراغ های IR روی دوربین ها در شرایطی است که ممکن است فاصله ی دوربین تا جسم خیلی زیاد نباشد.

SMART IR

(DNR(Digital Noise Redctron

کاهش نویز تصویر در محیط های با نور پایین (تصویر تهیه شده در شب).
دوربین های با امکان DNR در مقایسه با دوربین هایی که امکان DNR ندارند نویز کمتری ایجاد می کنند.

(DNR(Digital Noise Redctron

HLC Highlight Compensation

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

HLC Highlight Compensation

الگوریتم Canny

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

  • تضعیف نویز
  • پیدا کردن نقاطی که بتوان آنها را به عنوان لبه در نظر گرفت
  • جذب نقاطی که احتمال لبه بودن آنها کم است

 

معیارهایی که در لبه یاب کنی مطرح می باشد:
1 -پایین آوردن نرخ خطا- یعنی تا حد امکان هیچ لبه ای در تصویر نباید گم شود و هم چنین هیچ چیزی که لبه نیست نباید به جای لبه فرض شود. لبه هان پیدا شده تا حد ممکن به لبه ها اصلی
نزدیک باشند.

2 -لبه در مکان واقعی خود باشد- یعنی تا حد ممکن لبه ها کمترین فاصله را با مکان واقعی خود داشته باشند.
3 -بران هر لبه فقط یک پاسخ داشته باشیم.

4 -لبه ها کمترین ضخامت را داشته باشند- (در صورت امکان یک پیکسل).
لبه یاب کنی بخاطر توانایی در تولید لبه های نازک تا حد یک ییکسل برای لبه های پیوسته معروف شده است. این لبه یاب شامل چهار مرحله و چهار ورودی زیر است:
یک تصویر ورودی
یک پارامتر به نام سیگما جهت مقدار نرم کنندگی تصویر
یک حد آستانه بالا (Th)
یک حد آستانه پایین (Tl)

 

مراحل الگوریتم Canny:

1- در ابتدا باید تصویر رنگی را به جهت لبه یابی بهتر به یک تصویر سطح خاکسترن تبدیب کرد.

2- نویز را از تصویر دریافتی حذف کرد. بدلیل اینکه فیلتر گاوسین از یک ماسک ساده برای حذف نویز استفاده می کند لبه یاب کنی در مرحله اول برای حذف نویز آن را بکار می گیرد.

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

4- برخی از لبه های کشف شده واقعا لبه نیستند و در واقع نویز هستند که باید آنها توسط حد آستانه هیسترزیس فیلتر شوند.هیسترزیس از دو حد آستانه بالاتر (Th) و حد آستانه پایین تر (Tl) استفاده کرده و کنی پیشنهاد می کند که نسبت استانه بالا به پایین سه به یک باشد.

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

 

الگوریتم Canny    عملکرد الگوریتم Canny

 

 

کد الگوریتم Canny در C :

برنامه زیر یک فایل BMP سیاه و سفید 8 بیت در هر پیکسل را می خواند و نتیجه را در ‘out.bmp’ ذخیره می کند.با `-lm ‘ کامپایل می شود.

 

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
 
#define MAX_BRIGHTNESS 255
 
// C99 doesn't define M_PI (GNU-C99 does)
#define M_PI 3.14159265358979323846264338327
 
/*
 * Loading part taken from
 * http://www.vbforums.com/showthread.php?t=261522
 * BMP info:
 * http://en.wikipedia.org/wiki/BMP_file_format
 *
 * Note: the magic number has been removed from the bmpfile_header_t
 * structure since it causes alignment problems
 * bmpfile_magic_t should be written/read first
 * followed by the
 * bmpfile_header_t
 * [this avoids compiler-specific alignment pragmas etc.]
 */
 
typedef struct {
 uint8_t magic[2];
} bmpfile_magic_t;
 
typedef struct {
 uint32_t filesz;
 uint16_t creator1;
 uint16_t creator2;
 uint32_t bmp_offset;
} bmpfile_header_t;
 
typedef struct {
 uint32_t header_sz;
 int32_t width;
 int32_t height;
 uint16_t nplanes;
 uint16_t bitspp;
 uint32_t compress_type;
 uint32_t bmp_bytesz;
 int32_t hres;
 int32_t vres;
 uint32_t ncolors;
 uint32_t nimpcolors;
} bitmap_info_header_t;
 
typedef struct {
 uint8_t r;
 uint8_t g;
 uint8_t b;
 uint8_t nothing;
} rgb_t;
 
// Use short int instead `unsigned char' so that we can
// store negative values.
typedef short int pixel_t;
 
pixel_t *load_bmp(const char *filename,
 bitmap_info_header_t *bitmapInfoHeader)
{
 FILE *filePtr = fopen(filename, "rb");
 if (filePtr == NULL) {
 perror("fopen()");
 return NULL;
 }
 
 bmpfile_magic_t mag;
 if (fread(&mag, sizeof(bmpfile_magic_t), 1, filePtr) != 1) {
 fclose(filePtr);
 return NULL;
 }
 
 // verify that this is a bmp file by check bitmap id
 // warning: dereferencing type-punned pointer will break
 // strict-aliasing rules [-Wstrict-aliasing]
 if (*((uint16_t*)mag.magic) != 0x4D42) {
 fprintf(stderr, "Not a BMP file: magic=%c%c\n",
 mag.magic[0], mag.magic[1]);
 fclose(filePtr);
 return NULL;
 }
 
 bmpfile_header_t bitmapFileHeader; // our bitmap file header
 // read the bitmap file header
 if (fread(&bitmapFileHeader, sizeof(bmpfile_header_t),
 1, filePtr) != 1) {
 fclose(filePtr);
 return NULL;
 }
 
 // read the bitmap info header
 if (fread(bitmapInfoHeader, sizeof(bitmap_info_header_t),
 1, filePtr) != 1) {
 fclose(filePtr);
 return NULL;
 }
 
 if (bitmapInfoHeader->compress_type != 0)
 fprintf(stderr, "Warning, compression is not supported.\n");
 
 // move file point to the beginning of bitmap data
 if (fseek(filePtr, bitmapFileHeader.bmp_offset, SEEK_SET)) {
 fclose(filePtr);
 return NULL;
 }
 
 // allocate enough memory for the bitmap image data
 pixel_t *bitmapImage = malloc(bitmapInfoHeader->bmp_bytesz *
 sizeof(pixel_t));
 
 // verify memory allocation
 if (bitmapImage == NULL) {
 fclose(filePtr);
 return NULL;
 }
 
 // read in the bitmap image data
 size_t pad, count=0;
 unsigned char c;
 pad = 4*ceil(bitmapInfoHeader->bitspp*bitmapInfoHeader->width/32.) - bitmapInfoHeader->width;
 for(size_t i=0; i<bitmapInfoHeader->height; i++){
 for(size_t j=0; j<bitmapInfoHeader->width; j++){
 if (fread(&c, sizeof(unsigned char), 1, filePtr) != 1) {
 fclose(filePtr);
 return NULL;
 }
 bitmapImage[count++] = (pixel_t) c;
 }
 fseek(filePtr, pad, SEEK_CUR);
 }
 
 // If we were using unsigned char as pixel_t, then:
 // fread(bitmapImage, 1, bitmapInfoHeader->bmp_bytesz, filePtr);
 
 // close file and return bitmap image data
 fclose(filePtr);
 return bitmapImage;
}
 
// Return: true on error.
bool save_bmp(const char *filename, const bitmap_info_header_t *bmp_ih,
 const pixel_t *data)
{
 FILE* filePtr = fopen(filename, "wb");
 if (filePtr == NULL)
 return true;
 
 bmpfile_magic_t mag = {{0x42, 0x4d}};
 if (fwrite(&mag, sizeof(bmpfile_magic_t), 1, filePtr) != 1) {
 fclose(filePtr);
 return true;
 }
 
 const uint32_t offset = sizeof(bmpfile_magic_t) +
 sizeof(bmpfile_header_t) +
 sizeof(bitmap_info_header_t) +
 ((1U << bmp_ih->bitspp) * 4);
 
 const bmpfile_header_t bmp_fh = {
 .filesz = offset + bmp_ih->bmp_bytesz,
 .creator1 = 0,
 .creator2 = 0,
 .bmp_offset = offset
 };
 
 if (fwrite(&bmp_fh, sizeof(bmpfile_header_t), 1, filePtr) != 1) {
 fclose(filePtr);
 return true;
 }
 if (fwrite(bmp_ih, sizeof(bitmap_info_header_t), 1, filePtr) != 1) {
 fclose(filePtr);
 return true;
 }
 
 // Palette
 for (size_t i = 0; i < (1U << bmp_ih->bitspp); i++) {
 const rgb_t color = {(uint8_t)i, (uint8_t)i, (uint8_t)i};
 if (fwrite(&color, sizeof(rgb_t), 1, filePtr) != 1) {
 fclose(filePtr);
 return true;
 }
 }
 
 // We use int instead of uchar, so we can't write img
 // in 1 call any more.
 // fwrite(data, 1, bmp_ih->bmp_bytesz, filePtr);
 
 // Padding: http://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage
 size_t pad = 4*ceil(bmp_ih->bitspp*bmp_ih->width/32.) - bmp_ih->width;
 unsigned char c;
 for(size_t i=0; i < bmp_ih->height; i++) {
 for(size_t j=0; j < bmp_ih->width; j++) {
 c = (unsigned char) data[j + bmp_ih->width*i];
 if (fwrite(&c, sizeof(char), 1, filePtr) != 1) {
 fclose(filePtr);
 return true;
 }
 }
 c = 0;
 for(size_t j=0; j<pad; j++)
 if (fwrite(&c, sizeof(char), 1, filePtr) != 1) {
 fclose(filePtr);
 return true;
 }
 }
 
 fclose(filePtr);
 return false;
}
 
// if normalize is true, map pixels to range 0..MAX_BRIGHTNESS
void convolution(const pixel_t *in, pixel_t *out, const float *kernel,
 const int nx, const int ny, const int kn,
 const bool normalize)
{
 assert(kn % 2 == 1);
 assert(nx > kn && ny > kn);
 const int khalf = kn / 2;
 float min = FLT_MAX, max = -FLT_MAX;
 
 if (normalize)
 for (int m = khalf; m < nx - khalf; m++)
 for (int n = khalf; n < ny - khalf; n++) {
 float pixel = 0.0;
 size_t c = 0;
 for (int j = -khalf; j <= khalf; j++)
 for (int i = -khalf; i <= khalf; i++) {
 pixel += in[(n - j) * nx + m - i] * kernel;
 c++;
 }
 if (pixel < min)
 min = pixel;
 if (pixel > max)
 max = pixel;
 }
 
 for (int m = khalf; m < nx - khalf; m++)
 for (int n = khalf; n < ny - khalf; n++) {
 float pixel = 0.0;
 size_t c = 0;
 for (int j = -khalf; j <= khalf; j++)
 for (int i = -khalf; i <= khalf; i++) {
 pixel += in[(n - j) * nx + m - i] * kernel;
 c++;
 }
 
 if (normalize)
 pixel = MAX_BRIGHTNESS * (pixel - min) / (max - min);
 out[n * nx + m] = (pixel_t)pixel;
 }
}
 
/*
 * gaussianFilter:
 * http://www.songho.ca/dsp/cannyedge/cannyedge.html
 * determine size of kernel (odd #)
 * 0.0 <= sigma < 0.5 : 3
 * 0.5 <= sigma < 1.0 : 5
 * 1.0 <= sigma < 1.5 : 7
 * 1.5 <= sigma < 2.0 : 9
 * 2.0 <= sigma < 2.5 : 11
 * 2.5 <= sigma < 3.0 : 13 ...
 * kernelSize = 2 * int(2*sigma) + 3;
 */
void gaussian_filter(const pixel_t *in, pixel_t *out,
 const int nx, const int ny, const float sigma)
{
 const int n = 2 * (int)(2 * sigma) + 3;
 const float mean = (float)floor(n / 2.0);
 float kernel[n * n]; // variable length array
 
 fprintf(stderr, "gaussian_filter: kernel size %d, sigma=%g\n",
 n, sigma);
 size_t c = 0;
 for (int i = 0; i < n; i++)
 for (int j = 0; j < n; j++) {
 kernel = exp(-0.5 * (pow((i - mean) / sigma, 2.0) +
 pow((j - mean) / sigma, 2.0)))
 / (2 * M_PI * sigma * sigma);
 c++;
 }
 
 convolution(in, out, kernel, nx, ny, n, true);
}
 
/*
 * Links:
 * http://en.wikipedia.org/wiki/Canny_edge_detector
 * http://www.tomgibara.com/computer-vision/CannyEdgeDetector.java
 * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
 * http://www.songho.ca/dsp/cannyedge/cannyedge.html
 *
 * Note: T1 and T2 are lower and upper thresholds.
 */
pixel_t *canny_edge_detection(const pixel_t *in,
 const bitmap_info_header_t *bmp_ih,
 const int tmin, const int tmax,
 const float sigma)
{
 const int nx = bmp_ih->width;
 const int ny = bmp_ih->height;
 
 pixel_t *G = calloc(nx * ny * sizeof(pixel_t), 1);
 pixel_t *after_Gx = calloc(nx * ny * sizeof(pixel_t), 1);
 pixel_t *after_Gy = calloc(nx * ny * sizeof(pixel_t), 1);
 pixel_t *nms = calloc(nx * ny * sizeof(pixel_t), 1);
 pixel_t *out = malloc(bmp_ih->bmp_bytesz * sizeof(pixel_t));
 
 if (G == NULL || after_Gx == NULL || after_Gy == NULL ||
 nms == NULL || out == NULL) {
 fprintf(stderr, "canny_edge_detection:"
 " Failed memory allocation(s).\n");
 exit(1);
 }
 
 gaussian_filter(in, out, nx, ny, sigma);
 
 const float Gx[] = {-1, 0, 1,
 -2, 0, 2,
 -1, 0, 1};
 
 convolution(out, after_Gx, Gx, nx, ny, 3, false);
 
 const float Gy[] = { 1, 2, 1,
 0, 0, 0,
 -1,-2,-1};
 
 convolution(out, after_Gy, Gy, nx, ny, 3, false);
 
 for (int i = 1; i < nx - 1; i++)
 for (int j = 1; j < ny - 1; j++) {
 const int c = i + nx * j;
 // G = abs(after_Gx) + abs(after_Gy);
 G = (pixel_t)hypot(after_Gx, after_Gy);
 }
 
 // Non-maximum suppression, straightforward implementation.
 for (int i = 1; i < nx - 1; i++)
 for (int j = 1; j < ny - 1; j++) {
 const int c = i + nx * j;
 const int nn = c - nx;
 const int ss = c + nx;
 const int ww = c + 1;
 const int ee = c - 1;
 const int nw = nn + 1;
 const int ne = nn - 1;
 const int sw = ss + 1;
 const int se = ss - 1;
 
 const float dir = (float)(fmod(atan2(after_Gy,
 after_Gx) + M_PI,
 M_PI) / M_PI) * 8;
 
 if (((dir <= 1 || dir > 7) && G > G[ee] &&
 G > G[ww]) || // 0 deg
 ((dir > 1 && dir <= 3) && G > G[nw] &&
 G > G[se]) || // 45 deg
 ((dir > 3 && dir <= 5) && G > G[nn] &&
 G > G[ss]) || // 90 deg
 ((dir > 5 && dir <= 7) && G > G[ne] &&
 G > G[sw])) // 135 deg
 nms = G;
 else
 nms = 0;
 }
 
 // Reuse array
 // used as a stack. nx*ny/2 elements should be enough.
 int *edges = (int*) after_Gy;
 memset(out, 0, sizeof(pixel_t) * nx * ny);
 memset(edges, 0, sizeof(pixel_t) * nx * ny);
 
 // Tracing edges with hysteresis . Non-recursive implementation.
 size_t c = 1;
 for (int j = 1; j < ny - 1; j++)
 for (int i = 1; i < nx - 1; i++) {
 if (nms >= tmax && out == 0) { // trace edges
 out = MAX_BRIGHTNESS;
 int nedges = 1;
 edges[0] = c;
 
 do {
 nedges--;
 const int t = edges[nedges];
 
 int nbs[8]; // neighbours
 nbs[0] = t - nx; // nn
 nbs[1] = t + nx; // ss
 nbs[2] = t + 1; // ww
 nbs[3] = t - 1; // ee
 nbs[4] = nbs[0] + 1; // nw
 nbs[5] = nbs[0] - 1; // ne
 nbs[6] = nbs[1] + 1; // sw
 nbs[7] = nbs[1] - 1; // se
 
 for (int k = 0; k < 8; k++)
 if (nms[nbs[k]] >= tmin && out[nbs[k]] == 0) {
 out[nbs[k]] = MAX_BRIGHTNESS;
 edges[nedges] = nbs[k];
 nedges++;
 }
 } while (nedges > 0);
 }
 c++;
 }
 
 free(after_Gx);
 free(after_Gy);
 free(G);
 free(nms);
 
 return out;
}
 
int main(const int argc, const char ** const argv)
{
 if (argc < 2) {
 printf("Usage: %s image.bmp\n", argv[0]);
 return 1;
 }
 
 static bitmap_info_header_t ih;
 const pixel_t *in_bitmap_data = load_bmp(argv[1], &ih);
 if (in_bitmap_data == NULL) {
 fprintf(stderr, "main: BMP image not loaded.\n");
 return 1;
 }
 
 printf("Info: %d x %d x %d\n", ih.width, ih.height, ih.bitspp);
 
 const pixel_t *out_bitmap_data =
 canny_edge_detection(in_bitmap_data, &ih, 45, 50, 1.0f);
 if (out_bitmap_data == NULL) {
 fprintf(stderr, "main: failed canny_edge_detection.\n");
 return 1;
 }
 
 if (save_bmp("out.bmp", &ih, out_bitmap_data)) {
 fprintf(stderr, "main: BMP image not saved.\n");
 return 1;
 }
 
 free((pixel_t*)in_bitmap_data);
 free((pixel_t*)out_bitmap_data);
 return 0;
}

 

دانلود کد فوق از طریق لینک زیر:

Canny in C

رمز فایل : behsanandish.com

الگوریتم Canny

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

  • تضعیف نویز
  • پیدا کردن نقاطی که بتوان آنها را به عنوان لبه در نظر گرفت
  • حذب نقاطی که احتمال لبه بودن آنها کم است

 

معیارهایی که در لبه یاب کنی مطرح است:
1 -پایین آوردن نرخ خطا- یعنی تا حد امکان هیچ لبه ای در تصویر نباید گم شود و هم چنین هیچ چیزی که لبه نیست نباید به جای لبه فرض شود. لبه هان پیدا شده تا حد ممکن به لبه ها اصلی
نزدیک باشند.

2 -لبه در مکان واقعی خود باشد- یعنی تا حد ممکن لبه ها کمترین فاصله را با مکان واقعی خود داشته باشند.
3 -بران هر لبه فقط یک پاسخ داشته باشیم.

4 -لبه ها کمترین ضخامت را داشته باشند- (در صورت امکان یک پیکسل).
لبه یاب کنی بخاطر توانایی در تولید لبه های نازک تا حد یک ییکسل برای لبه های پیوسته معروف شده است. این لبه یاب شامل چهار مرحله و چهار ورودی زیر است:
یک تصویر ورودی
یک پارامتر به نام سیگما جهت مقدار نرم کنندگی تصویر
یک حد آستانه بالا (Th)
یک حد آستانه پایین (Tl)

 

مراحل الگوریتم Canny:

1- در ابتدا باید تصویر رنگی را به جهت لبه یابی بهتر به یک تصویر سطح خاکسترن تبدیب کرد.

2- نویز را از تصویر دریافتی حذف کرد. بدلیل اینکه فیلتر گاوسین از یک ماسک ساده برای حذف نویز استفاده می کند لبه یاب کنی در مرحله اول برای حذف نویز آن را بکار میگیرد.

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

4- برخی از لبه های کشف شده واقعا لبه نیستند و در واقع نویز هستند که باید آنها توسط حد آستانه هیسترزیس فیلتر شوند.هیسترزیس از دو حد آستانه بالاتر (Th) و حد آستانه پایین تر (Tl) استفاده کرده و کنی پیشنهاد می کند که نسبت استانه بالا به پایین سه به یک باشد.

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

 

 

الگوریتم Canny    عملکرد الگوریتم Canny

 

کد الگوریتم Canny در OpenCV:

 

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>

using namespace cv;

/// Global variables

Mat src, src_gray;
Mat dst, detected_edges;

int edgeThresh = 1;
int lowThreshold;
int const max_lowThreshold = 100;
int ratio = 3;
int kernel_size = 3;
char* window_name = "Edge Map";

/**
 * @function CannyThreshold
 * @brief Trackbar callback - Canny thresholds input with a ratio 1:3
 */
void CannyThreshold(int, void*)
{
  /// Reduce noise with a kernel 3x3
  blur( src_gray, detected_edges, Size(3,3) );

  /// Canny detector
  Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );

  /// Using Canny's output as a mask, we display our result
  dst = Scalar::all(0);

  src.copyTo( dst, detected_edges);
  imshow( window_name, dst );
 }

/** @function main */
int main( int argc, char** argv )
{
  /// Load an image
  src = imread( argv[1] );

  if( !src.data )
  { return -1; }</pre>
<pre>  /// Create a matrix of the same type and size as src (for dst)
  dst.create( src.size(), src.type() );

  /// Convert the image to grayscale
  cvtColor( src, src_gray, CV_BGR2GRAY );

  /// Create a window
  namedWindow( window_name, CV_WINDOW_AUTOSIZE );

  /// Create a Trackbar for user to enter threshold
  createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );

  /// Show the image
  CannyThreshold(0, 0);

  /// Wait until user exit program by pressing a key
  waitKey(0);

  return 0;
  }

 

 

دانلود کد فوق از طریق لینک زیر:

CannyInOpenCV

رمز فایل : behsanandish.com

 

الگوریتم Canny

لبه یاب کنی توسط جان اف کنی در سال 1986 ایجاد شد و هنوز یک لبه یاب استاندارد و با دقت و کیفیت بالا میباشد.الگوریتم لبه یابی کنی یکی از بهترین لبه یابها تا به امروز است. در ادامه روش کار این الگوریتم و هم چنین کد الگوریتم Canny در #C را بررسی خواهیم کرد. این الگوریتم لبه یابی از سه بخش اصلی زیر تشکیل شده:

  • تضعیف نویز
  • پیدا کردن نقاطی که بتوان آنها را به عنوان لبه در نظر گرفت
  • حذب نقاطی که احتمال لبه بودن آنها کم است

 

معیارهایی که در لبه یاب کنی مطرح است:
1 -پایین آوردن نرخ خطا- یعنی تا حد امکان هیچ لبه ای در تصویر نباید گم شود و هم چنین هیچ چیزی که لبه نیست نباید به جای لبه فرض شود. لبه هان پیدا شده تا حد ممکن به لبه ها اصلی
نزدیک باشند.

2 -لبه در مکان واقعی خود باشد- یعنی تا حد ممکن لبه ها کمترین فاصله را با مکان واقعی خود داشته باشند.
3 -بران هر لبه فقط یک پاسخ داشته باشیم.

4 -لبه ها کمترین ضخامت را داشته باشند- (در صورت امکان یک پیکسل).
لبه یاب کنی بخاطر توانایی در تولید لبه های نازک تا حد یک ییکسل برای لبه های پیوسته معروف شده است. این لبه یاب شامل چهار مرحله و چهار ورودی زیر است:
یک تصویر ورودی
یک پارامتر به نام سیگما جهت مقدار نرم کنندگی تصویر
یک حد آستانه بالا (Th)
یک حد آستانه پایین (Tl)

 

مراحل الگوریتم Canny:

1- در ابتدا باید تصویر رنگی را به جهت لبه یابی بهتر به یک تصویر سطح خاکسترن تبدیب کرد.

2- نویز را از تصویر دریافتی حذف کرد. بدلیل اینکه فیلتر گاوسین از یک ماسک ساده برای حذف نویز استفاده می کند لبه یاب کنی در مرحله اول برای حذف نویز آن را بکار میگیرد.

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

4- برخی از لبه های کشف شده واقعا لبه نیستند و در واقع نویز هستند که باید آنها توسط حد آستانه هیسترزیس فیلتر شوند.هیسترزیس از دو حد آستانه بالاتر (Th) و حد آستانه پایین تر (Tl) استفاده کرده و کنی پیشنهاد می کند که نسبت استانه بالا به پایین سه به یک باشد.

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

 

الگوریتم Canny    عملکرد الگوریتم Canny

 


 

کد الگوریتم Canny در #C:

الگوریتم در 5 مرحله جداگانه اجرا می شود:

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

private void GenerateGaussianKernel(int N, float S ,out int Weight)
{

float Sigma = S ;
float pi;
pi = (float)Math.PI;
int i, j;
int SizeofKernel=N;

float [,] Kernel = new float [N,N];
GaussianKernel = new int [N,N];
float[,] OP = new float[N, N];
float D1,D2;

D1= 1/(2*pi*Sigma*Sigma);
D2= 2*Sigma*Sigma;

float min=1000;

for (i = -SizeofKernel / 2; i <= SizeofKernel / 2; i++)
{
for (j = -SizeofKernel / 2; j <= SizeofKernel / 2; j++)
{
Kernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j] = ((1 / D1) * (float)Math.Exp(-(i * i + j * j) / D2));
if (Kernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j] < min)
min = Kernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j];

}
}
int mult = (int)(1 / min);
int sum = 0;
if ((min > 0) && (min < 1))
{

for (i = -SizeofKernel / 2; i <= SizeofKernel / 2; i++)
{
for (j = -SizeofKernel / 2; j <= SizeofKernel / 2; j++)
{
Kernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j] = (float)Math.Round(Kernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j] * mult, 0);
GaussianKernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j] = (int)Kernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j];
sum = sum + GaussianKernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j];
}

}

}
else
{
sum = 0;
for (i = -SizeofKernel / 2; i <= SizeofKernel / 2; i++)
{
for (j = -SizeofKernel / 2; j <= SizeofKernel / 2; j++)
{
Kernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j] = (float)Math.Round(Kernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j] , 0);
GaussianKernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j] = (int)Kernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j];
sum = sum + GaussianKernel[SizeofKernel / 2 + i, SizeofKernel / 2 + j];
}

}

}
//Normalizing kernel Weight
Weight= sum;

return;
}

 

زیر روال ذیل نویز را توسط فیلتر گوسی حذف می کند.

 

private int[,] GaussianFilter(int[,] Data)
        {
            GenerateGaussianKernel(KernelSize, Sigma,out KernelWeight);

            int[,] Output = new int[Width, Height];
            int i, j,k,l;
            int Limit = KernelSize /2;

            float Sum=0;

 Output = Data; // Removes Unwanted Data Omission due to kernel bias while convolution

            for (i = Limit; i <= ((Width - 1) - Limit); i++)
            {
                for (j = Limit; j <= ((Height - 1) - Limit); j++)
                {
                    Sum = 0;
                    for (k = -Limit; k <= Limit; k++)
                    {

                       for (l = -Limit; l <= Limit; l++)
                        {
                            Sum = Sum + ((float)Data[i + k, j + l] * GaussianKernel [Limit + k, Limit + l]);                        

                        }
                    }
                    Output[i, j] = (int)(Math.Round(Sum/ (float)KernelWeight));
                }

            }

            return Output;
        }

 

2. پیدا کردن شیب ها: لبه ها باید مشخص شوند، جایی که شیب های تصویر بزرگ می شوند.

ماسک های سوبل  X و Y برای تولید گرادیان های تصویر X و Y استفاده می شود؛ تابع بعدی تمایز را با استفاده از فیلتر ماسک sobel اعمال می کند.

 

private float[,] Differentiate(int[,] Data, int[,] Filter)
        {
            int i, j,k,l, Fh, Fw;

            Fw = Filter.GetLength(0);
            Fh = Filter.GetLength(1);
            float sum = 0;
            float[,] Output = new float[Width, Height];

            for (i = Fw / 2; i <= (Width - Fw / 2) - 1; i++)
            {
                for (j = Fh / 2; j <= (Height  - Fh / 2) - 1; j++)
                {
                  sum=0;
                   for(k=-Fw/2; k<=Fw/2; k++)
                   {
                       for(l=-Fh/2; l<=Fh/2; l++)
                       {
                          sum=sum + Data[i+k,j+l]*Filter[Fw/2+k,Fh/2+l];


                       }
                   }
                    Output[i,j]=sum;

                }

            }
            return Output;

        }

 

3. توقیف غیر حداکثر: فقط حداکثرهای محلی باید به عنوان لبه ها مشخص شود.

ما جهت گرادیان را پیدا می کنیم و با استفاده از این جهت، ما توقیف غیر حداکثر را انجام می دهیم (“پردازش تصویر دیجیتال- آموزش توسط گنزالس-پیرسون ” را بخوانید)

 

// Perform Non maximum suppression:
           // NonMax = Gradient;

            for (i = 0; i <= (Width - 1); i++)
            {
                for (j = 0; j <= (Height - 1); j++)
                {
                    NonMax[i, j] = Gradient[i, j];
                }
            }
     
            int Limit = KernelSize / 2;
            int r, c;
            float Tangent;

                for (i = Limit; i <= (Width - Limit) - 1; i++)
            {
                for (j = Limit; j <= (Height - Limit) - 1; j++)
                {

                    if (DerivativeX[i, j] == 0)
                        Tangent = 90F;
                    else
                        Tangent = (float)(Math.Atan(DerivativeY[i, j] / DerivativeX[i, j]) * 180 / Math.PI); //rad to degree



                    //Horizontal Edge
                    if (((-22.5 < Tangent) && (Tangent <= 22.5)) || ((157.5 < Tangent) && (Tangent <= -157.5)))
                    {
                        if ((Gradient[i, j] < Gradient[i, j + 1]) || (Gradient[i, j] < Gradient[i, j - 1]))
                            NonMax[i, j] = 0;
                    }

                    //Vertical Edge
                    if (((-112.5 < Tangent) && (Tangent <= -67.5)) || ((67.5 < Tangent) && (Tangent <= 112.5)))
                    {
                        if ((Gradient[i, j] < Gradient[i + 1, j]) || (Gradient[i, j] < Gradient[i - 1, j]))
                            NonMax[i, j] = 0;
                    }

                    //+45 Degree Edge
                    if (((-67.5 < Tangent) && (Tangent <= -22.5)) || ((112.5 < Tangent) && (Tangent <= 157.5)))
                    {
                        if ((Gradient[i, j] < Gradient[i + 1, j - 1]) || (Gradient[i, j] < Gradient[i - 1, j + 1]))
                            NonMax[i, j] = 0;
                    }

                    //-45 Degree Edge
                    if (((-157.5 < Tangent) && (Tangent <= -112.5)) || ((67.5 < Tangent) && (Tangent <= 22.5)))
                    {
                        if ((Gradient[i, j] < Gradient[i + 1, j + 1]) || (Gradient[i, j] < Gradient[i - 1, j - 1]))
                            NonMax[i, j] = 0;
                    }

                }

            }

 

4. آستانه دوگانه: لبه های بالقوه توسط آستانه تعیین می شود.

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

 

private void HysterisisThresholding(int[,] Edges)
        {

            int i, j;
            int Limit= KernelSize/2;


            for (i = Limit; i <= (Width - 1) - Limit; i++)
                for (j = Limit; j <= (Height - 1) - Limit; j++)
                {
                    if (Edges[i, j] == 1)
                    {
                        EdgeMap[i, j] = 1;

                    }

                }

            for (i = Limit; i <= (Width - 1) - Limit; i++)
            {
                for (j = Limit; j <= (Height  - 1) - Limit; j++)
                {
                    if (Edges[i, j] == 1)
                    {
                        EdgeMap[i, j] = 1;
                        Travers(i, j);
                        VisitedMap[i, j] = 1;
                    }
                }
            }




            return;
        }

//Recursive Procedure 
private void Travers(int X, int Y)
        {

            
            if (VisitedMap[X, Y] == 1)
            {
                return;
            }

            //1
            if (EdgePoints[X + 1, Y] == 2)
            {
                EdgeMap[X + 1, Y] = 1;
                VisitedMap[X + 1, Y] = 1;
                Travers(X + 1, Y);
                return;
            }
            //2
            if (EdgePoints[X + 1, Y - 1] == 2)
            {
                EdgeMap[X + 1, Y - 1] = 1;
                VisitedMap[X + 1, Y - 1] = 1;
                Travers(X + 1, Y - 1);
                return;
            }

           //3

            if (EdgePoints[X, Y - 1] == 2)
            {
                EdgeMap[X , Y - 1] = 1;
                VisitedMap[X , Y - 1] = 1;
                Travers(X , Y - 1);
                return;
            }

           //4

            if (EdgePoints[X - 1, Y - 1] == 2)
            {
                EdgeMap[X - 1, Y - 1] = 1;
                VisitedMap[X - 1, Y - 1] = 1;
                Travers(X - 1, Y - 1);
                return;
            }
            //5
            if (EdgePoints[X - 1, Y] == 2)
            {
                EdgeMap[X - 1, Y ] = 1;
                VisitedMap[X - 1, Y ] = 1;
                Travers(X - 1, Y );
                return;
            }
            //6
            if (EdgePoints[X - 1, Y + 1] == 2)
            {
                EdgeMap[X - 1, Y + 1] = 1;
                VisitedMap[X - 1, Y + 1] = 1;
                Travers(X - 1, Y + 1);
                return;
            }
            //7
            if (EdgePoints[X, Y + 1] == 2)
            {
                EdgeMap[X , Y + 1] = 1;
                VisitedMap[X, Y + 1] = 1;
                Travers(X , Y + 1);
                return;
            }
            //8

            if (EdgePoints[X + 1, Y + 1] == 2)
            {
                EdgeMap[X + 1, Y + 1] = 1;
                VisitedMap[X + 1, Y + 1] = 1;
                Travers(X + 1, Y + 1);
                return;
            }


            //VisitedMap[X, Y] = 1;
            return;

        } 
          
        //Canny Class Ends

    }

 

این کار با یک تابع بازگشتی انجام می شود که آستانه دوگانه را با دو آستانه بالا (Threshold (TH و (Low Threshold (TL و تجزیه و تحلیل 8-اتصال انجام می دهد.

 

دانلود کد فوق از طریق لینک زیر:

Canny Edge Detection C#

رمز فایل : behsanandish.com


الگوریتم sobel

کد الگوریتم سوبل – متد سوبل لبه ها را با استفاده از تخمین زدن مشتق پیدا می کند، که لبه ها را در آن نقاطی بر می گرداند که گرادیان تصویر I ، max است. پیشنهاد می کنیم جهت آشنایی با الگوریتم های لبه یابی، مطلب «الگوریتم های لبه یابی و انواع آن» را مشاهده نمایید. در فیلتر سوبل دو ماسک به صورت زیر وجود دارد:

ماسک سوبل عمودی         ماسک سوبل افقی

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

براي مشخص شدن کلیه لبه ها:
اگر Gو Gy تصاویر فیلتر شده به وسیله ماسک افقی و عمودي باشند، آنگاه تصویر  فرمول الگوریتم سوبل    لبه هاي تصویر را بهتر نشان میدهد. روال فوق به عملگر یا الگورریتم سوبل موسوم است.
در عمل، به منظور کاهش هزینه محاسبات، به جاي  فرمول الگوریتم سوبل  میتوان از تقریب [Gx] + [Gy] استفاده میشود. توجه شود که نتیجه این دو فرمول تقریبا یکسان است ولی فرمول دوم با هزینه کمتري قابل محاسبه می باشد.

تأثیر عملگر سوبل بر لبه یابی تصاویر

 

کد الگوریتم سوبل( Sobel ) در Matlab:

 

clc; clear; close all; warning off; 

I=imread('lena.bmp');
I=im2double(I);
I=imnoise(I, 'gaussian', 0, 0.001);
figure(1);
imshow(I);title('org img');

[height width R]=size(I);

for i=2:height-1
    for j=2:width-1
        Dx(i,j)=[I(i+1,j-1)-I(i-1,j-1)]+2*[I(i+1,j)-I(i-1,j)]+[I(i+1,j+1)-I(i-1,j+1)];
        Dy(i,j)=[I(i-1,j+1)-I(i-1,j-1)]+2*[I(i,j+1)-I(i,j-1)]+[I(i+1,j+1)-I(i+1,j-1)];
        S(i,j)=sqrt(Dx(i,j)^2+Dy(i,j)^2);
        if Dx(i,j)&amp;lt;1
            Dx(i,j)=0;
        else Dx(i,j)=1;
        end
        if Dy(i,j)&amp;lt;1
            Dy(i,j)=0;
        else Dy(i,j)=1;
        end
    end
end
figure(2);
imshow(Dx,[]);

figure(3);
imshow(Dy,[]);

for i=1:255
    for j=1:255
       if (S(i,j)&amp;lt;1)
            S(i,j)=0;
        else S(i,j)=1;
        end
    end
end
figure(4);
imshow(S,[]);
دانلود کد فوق از طریق لینک زیر:

الگوریتم سوبل به زبان متلب

رمز فایل : behsanandish.com


 

کد الگوریتم سوبل( Sobel ) در #C:

1.کد برای فیلتر کانولوشن: بخش اول این تابع برای گرفتن اطلاعات تصویر و ذخیره آن به آرایه اختصاص داده شده است.

 

private static Bitmap ConvolutionFilter(Bitmap sourceImage, 
    double[,] xkernel, 
    double[,] ykernel, double factor = 1, int bias = 0, bool grayscale = false)
{

    //Image dimensions stored in variables for convenience
    int width = sourceImage.Width;
    int height = sourceImage.Height;

     //Lock source image bits into system memory
    BitmapData srcData = sourceImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

     //Get the total number of bytes in your image - 32 bytes per pixel x image width x image height -&amp;gt; for 32bpp images
    int bytes = srcData.Stride * srcData.Height;

     //Create byte arrays to hold pixel information of your image
    byte[] pixelBuffer = new byte[bytes];
    byte[] resultBuffer = new byte[bytes];

     //Get the address of the first pixel data
    IntPtr srcScan0 = srcData.Scan0;

     //Copy image data to one of the byte arrays
    Marshal.Copy(srcScan0, pixelBuffer, 0, bytes);

    //Unlock bits from system memory -&amp;gt; we have all our needed info in the array
    sourceImage.UnlockBits(srcData);

 

2.کد تبدیل سیاه و سفید: از آنجایی که اپراتور Sobel اغلب برای تصاویر سیاه و سفید استفاده می شود، در اینجا یک کد برای تبدیل به سیاه و سفید است که توسط پارامتر boolean شما می توانید انتخاب کنید تبدیل کردن را یا نه.

 

//Convert your image to grayscale if necessary
if (grayscale == true)
{
    float rgb = 0;
    for (int i = 0; i &amp;lt; pixelBuffer.Length; i += 4)
    {
        rgb = pixelBuffer[i] * .21f;
        rgb += pixelBuffer[i + 1] * .71f;
        rgb += pixelBuffer[i + 2] * .071f;
        pixelBuffer[i] = (byte)rgb;
        pixelBuffer[i + 1] = pixelBuffer[i];
        pixelBuffer[i + 2] = pixelBuffer[i];
        pixelBuffer[i + 3] = 255;
    }
}

 

3.کد برای تنظیم متغیرهای مورد استفاده در فرآیند کانولوشن:

 

/Create variable for pixel data for each kernel
double xr = 0.0;
double xg = 0.0;
double xb = 0.0;
double yr = 0.0;
double yg = 0.0;
double yb = 0.0;
double rt = 0.0;
double gt = 0.0;
double bt = 0.0;

//This is how much your center pixel is offset from the border of your kernel
//Sobel is 3x3, so center is 1 pixel from the kernel border
int filterOffset = 1;
int calcOffset = 0;
int byteOffset = 0;

//Start with the pixel that is offset 1 from top and 1 from the left side
//this is so entire kernel is on your image
for (int OffsetY = filterOffset; OffsetY &amp;lt; height - filterOffset; OffsetY++)
{
    for (int OffsetX = filterOffset; OffsetX &amp;lt; width - filterOffset; OffsetX++)
    {
        //reset rgb values to 0
        xr = xg = xb = yr = yg = yb = 0;
        rt = gt = bt = 0.0;

        //position of the kernel center pixel
        byteOffset = OffsetY * srcData.Stride + OffsetX * 4;

 

4. اعمال کانولوشن هسته به پیکسل فعلی:

 

//kernel calculations
for (int filterY = -filterOffset; filterY &amp;lt;= filterOffset; filterY++)
{
for (int filterX = -filterOffset; filterX &amp;lt;= filterOffset; filterX++)
{
calcOffset = byteOffset + filterX * 4 + filterY * srcData.Stride;
xb += (double)(pixelBuffer[calcOffset]) * xkernel[filterY + filterOffset, filterX + filterOffset];
xg += (double)(pixelBuffer[calcOffset + 1]) * xkernel[filterY + filterOffset, filterX + filterOffset];
xr += (double)(pixelBuffer[calcOffset + 2]) * xkernel[filterY + filterOffset, filterX + filterOffset];
yb += (double)(pixelBuffer[calcOffset]) * ykernel[filterY + filterOffset, filterX + filterOffset];
yg += (double)(pixelBuffer[calcOffset + 1]) * ykernel[filterY + filterOffset, filterX + filterOffset];
yr += (double)(pixelBuffer[calcOffset + 2]) * ykernel[filterY + filterOffset, filterX + filterOffset];
}
}

//total rgb values for this pixel
bt = Math.Sqrt((xb * xb) + (yb * yb));
gt = Math.Sqrt((xg * xg) + (yg * yg));
rt = Math.Sqrt((xr * xr) + (yr * yr));

//set limits, bytes can hold values from 0 up to 255;
if (bt &amp;gt; 255) bt = 255;
else if (bt &amp;lt; 0) bt = 0;
if (gt &amp;gt; 255) gt = 255;
else if (gt &amp;lt; 0) gt = 0;
if (rt &amp;gt; 255) rt = 255;
else if (rt &amp;lt; 0) rt = 0;

//set new data in the other byte array for your image data
resultBuffer[byteOffset] = (byte)(bt);
resultBuffer[byteOffset + 1] = (byte)(gt);
resultBuffer[byteOffset + 2] = (byte)(rt);
resultBuffer[byteOffset + 3] = 255;
}
}

 

5. کد خروجی تصویر پردازش شده:

 

//Create new bitmap which will hold the processed data
    Bitmap resultImage = new Bitmap(width, height);

    //Lock bits into system memory
    BitmapData resultData = resultImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

    //Copy from byte array that holds processed data to bitmap
    Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);

    //Unlock bits from system memory
    resultImage.UnlockBits(resultData);

    //Return processed image
    return resultImage;
}

 

6. کد برای هسته سوبل:

 

//Sobel operator kernel for horizontal pixel changes
private static double[,] xSobel
{
    get
    {
        return new double[,]
        {
            { -1, 0, 1 },
            { -2, 0, 2 },
            { -1, 0, 1 }
        };
    }
}

//Sobel operator kernel for vertical pixel changes
private static double[,] ySobel
{
    get
    {
        return new double[,]
        {
            {  1,  2,  1 },
            {  0,  0,  0 },
            { -1, -2, -1 }
        };
    }
}

 

همه این کد در اینجا موجود است (پروژه با ویژوال استودیو 2015 ایجاد شد):

SobelOperatorInC#

رمز فایل : behsanandish.com

 

کد الگوریتم sobel در #C

 


 

کد الگوریتم سوبل( Sobel ) در ++C:

در ادامه دو کد برای الگوریتم Sobel  در ++C آماده کردیم:

1.

 

#include&lt;iostream&gt;
#include&lt;cmath&gt;
#include&lt;opencv2/imgproc/imgproc.hpp&gt;
#include&lt;opencv2/highgui/highgui.hpp&gt;

using namespace std;
using namespace cv;

 
// Computes the x component of the gradient vector
// at a given point in a image.
// returns gradient in the x direction
int xGradient(Mat image, int x, int y)
{
    return image.at&lt;uchar&gt;(y-1, x-1) +
                2*image.at&lt;uchar&gt;(y, x-1) +
                 image.at&lt;uchar&gt;(y+1, x-1) -
                  image.at&lt;uchar&gt;(y-1, x+1) -
                   2*image.at&lt;uchar&gt;(y, x+1) -
                    image.at&lt;uchar&gt;(y+1, x+1);
}

// Computes the y component of the gradient vector
// at a given point in a image
// returns gradient in the y direction

int yGradient(Mat image, int x, int y)
{
    return image.at&lt;uchar&gt;(y-1, x-1) +
                2*image.at&lt;uchar&gt;(y-1, x) +
                 image.at&lt;uchar&gt;(y-1, x+1) -
                  image.at&lt;uchar&gt;(y+1, x-1) -
                   2*image.at&lt;uchar&gt;(y+1, x) -
                    image.at&lt;uchar&gt;(y+1, x+1);
}

int main()
{

      Mat src, dst;
      int gx, gy, sum;

      // Load an image
      src = imread(&quot;lena.jpg&quot;, CV_LOAD_IMAGE_GRAYSCALE);
      dst = src.clone();
      if( !src.data )
      { return -1; }

        for(int y = 0; y &lt; src.rows; y++)
            for(int x = 0; x &lt; src.cols; x++)
                dst.at&lt;uchar&gt;(y,x) = 0.0;

        for(int y = 1; y &lt; src.rows - 1; y++){
            for(int x = 1; x &lt; src.cols - 1; x++){
                gx = xGradient(src, x, y);
                gy = yGradient(src, x, y);
                sum = abs(gx) + abs(gy);
                sum = sum &gt; 255 ? 255:sum;
                sum = sum &lt; 0 ? 0 : sum;
                dst.at&lt;uchar&gt;(y,x) = sum;
            }
        }

        namedWindow(&quot;final&quot;);
        imshow(&quot;final&quot;, dst);

        namedWindow(&quot;initial&quot;);
        imshow(&quot;initial&quot;, src);

      waitKey();

 
    return 0;
}

 

دانلود کد فوق از طریق لینک زیر:

Sobel in C++-Code1

رمز فایل : behsanandish.com

 

2.

 

#include &quot;itkImage.h&quot;
#include &quot;itkImageFileReader.h&quot;
#include &quot;itkImageFileWriter.h&quot;
#include &quot;itkSobelEdgeDetectionImageFilter.h&quot;

int main( int argc, char* argv[] )
{
  if( argc != 3 )
    {
    std::cerr &lt;&lt; &quot;Usage: &quot;&lt;&lt; std::endl;
    std::cerr &lt;&lt; argv[0];
    std::cerr &lt;&lt; &quot;&lt;InputFileName&gt; &lt;OutputFileName&gt;&quot;;
    std::cerr &lt;&lt; std::endl;
    return EXIT_FAILURE;
    }

  constexpr unsigned int Dimension = 2;

  using InputPixelType = unsigned char;
  using InputImageType = itk::Image&lt; InputPixelType, Dimension &gt;;

  using ReaderType = itk::ImageFileReader&lt; InputImageType &gt;;
  ReaderType::Pointer reader = ReaderType::New();
  reader-&gt;SetFileName( argv[1] );

  using OutputPixelType = float;
  using OutputImageType = itk::Image&lt; OutputPixelType, Dimension &gt;;

  using FilterType = itk::SobelEdgeDetectionImageFilter&lt; InputImageType, OutputImageType &gt;;
  FilterType::Pointer filter = FilterType::New();
  filter-&gt;SetInput( reader-&gt;GetOutput() );

  using WriterType = itk::ImageFileWriter&lt; OutputImageType &gt;;
  WriterType::Pointer writer = WriterType::New();
  writer-&gt;SetFileName( argv[2] );
  writer-&gt;SetInput( filter-&gt;GetOutput() );

  try
    {
    writer-&gt;Update();
    }
  catch( itk::ExceptionObject &amp; error )
    {
    std::cerr &lt;&lt; &quot;Error: &quot; &lt;&lt; error &lt;&lt; std::endl;
    return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;
}

 

دانلود کد فوق از طریق لینک زیر:

Sobel in C++-Code2

رمز فایل : behsanandish.com

 


کد الگوریتم سوبل( Sobel ) در C:

 

/* sobel.c */
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;float.h&gt;
#include &quot;mypgm.h&quot;

void sobel_filtering( )
     /* Spatial filtering of image data */
     /* Sobel filter (horizontal differentiation */
     /* Input: image1[y][x] ---- Outout: image2[y][x] */
{
  /* Definition of Sobel filter in horizontal direction */
  int weight[3][3] = {{ -1,  0,  1 },
      { -2,  0,  2 },
      { -1,  0,  1 }};
  double pixel_value;
  double min, max;
  int x, y, i, j;  /* Loop variable */

  /* Maximum values calculation after filtering*/
  printf(&quot;Now, filtering of input image is performed\n\n&quot;);
  min = DBL_MAX;
  max = -DBL_MAX;
  for (y = 1; y &lt; y_size1 - 1; y++) {
    for (x = 1; x &lt; x_size1 - 1; x++) {
      pixel_value = 0.0;
      for (j = -1; j &lt;= 1; j++) {
    for (i = -1; i &lt;= 1; i++) {
      pixel_value += weight[j + 1][i + 1] * image1[y + j][x + i];
    }
      }
      if (pixel_value &lt; min) min = pixel_value;
      if (pixel_value &gt; max) max = pixel_value;
    }
  }
  if ((int)(max - min) == 0) {
    printf(&quot;Nothing exists!!!\n\n&quot;);
    exit(1);
  }

  /* Initialization of image2[y][x] */
  x_size2 = x_size1;
  y_size2 = y_size1;
  for (y = 0; y &lt; y_size2; y++) {
    for (x = 0; x &lt; x_size2; x++) {
      image2[y][x] = 0;
    }
  }
  /* Generation of image2 after linear transformtion */
  for (y = 1; y &lt; y_size1 - 1; y++) {
    for (x = 1; x &lt; x_size1 - 1; x++) {
      pixel_value = 0.0;
      for (j = -1; j &lt;= 1; j++) {
    for (i = -1; i &lt;= 1; i++) {
      pixel_value += weight[j + 1][i + 1] * image1[y + j][x + i];
    }
      }
      pixel_value = MAX_BRIGHTNESS * (pixel_value - min) / (max - min);
      image2[y][x] = (unsigned char)pixel_value;
    }
  }
}

main( )
{
  load_image_data( );   /* Input of image1 */ 
  sobel_filtering( );   /* Sobel filter is applied to image1 */
  save_image_data( );   /* Output of image2 */
  return 0;
}
دانلود کد فوق از طریق لینک زیر:

Sobel in C

رمز فایل : behsanandish.com


 

کد الگوریتم سوبل( Sobel ) در Visual Basic:

 

Private Sub bEdge_Click(sender As Object, e As EventArgs) _
Handles bEdge.Click

'Sobel Edge'
Dim tmpImage As Bitmap = New Bitmap(picOriginal.Image)
Dim bmpImage As Bitmap = New Bitmap(picOriginal.Image)

Dim intWidth As Integer = tmpImage.Width
Dim intHeight As Integer = tmpImage.Height

Dim intOldX As Integer(,) = New Integer(,) {{-1, 0, 1}, _
{-2, 0, 2}, {-1, 0, 1}}
Dim intOldY As Integer(,) = New Integer(,) {{1, 2, 1}, _
{0, 0, 0}, {-1, -2, -1}}

Dim intR As Integer(,) = New Integer(intWidth - 1, _
intHeight - 1) {}
Dim intG As Integer(,) = New Integer(intWidth - 1, _
intHeight - 1) {}
Dim intB As Integer(,) = New Integer(intWidth - 1, _
intHeight - 1) {}

Dim intMax As Integer = 128 * 128

For i As Integer = 0 To intWidth - 1

For j As Integer = 0 To intHeight - 1

intR(i, j) = tmpImage.GetPixel(i, j).R
intG(i, j) = tmpImage.GetPixel(i, j).G
intB(i, j) = tmpImage.GetPixel(i, j).B

Next

Next

Dim intRX As Integer = 0
Dim intRY As Integer = 0
Dim intGX As Integer = 0
Dim intGY As Integer = 0
Dim intBX As Integer = 0
Dim intBY As Integer = 0

Dim intRTot As Integer
Dim intGTot As Integer
Dim intBTot As Integer

For i As Integer = 1 To tmpImage.Width - 1 - 1

For j As Integer = 1 To tmpImage.Height - 1 - 1

intRX = 0
intRY = 0
intGX = 0
intGY = 0
intBX = 0
intBY = 0

intRTot = 0
intGTot = 0
intBTot = 0

For width As Integer = -1 To 2 - 1

For height As Integer = -1 To 2 - 1

intRTot = intR(i + height, j + width)
intRX += intOldX(width + 1, height + 1) * intRTot
intRY += intOldY(width + 1, height + 1) * intRTot

intGTot = intG(i + height, j + width)
intGX += intOldX(width + 1, height + 1) * intGTot
intGY += intOldY(width + 1, height + 1) * intGTot

intBTot = intB(i + height, j + width)
intBX += intOldX(width + 1, height + 1) * intBTot
intBY += intOldY(width + 1, height + 1) * intBTot

Next

Next

If intRX * intRX + intRY * intRY &gt; intMax OrElse
intGX * intGX + intGY * intGY &gt; intMax OrElse
intBX * intBX + intBY * intBY &gt; intMax Then

bmpImage.SetPixel(i, j, Color.Black)

Else

bmpImage.SetPixel(i, j, Color.Transparent)

End If

Next

Next

picModified.Image = bmpImage

End Sub
دانلود کد فوق از طریق لینک زیر:

Sobel in VB

رمز فایل : behsanandish.com

 

کد الگوریتم sobel در VB

 


 

پیشنهاد می کنیم جهت آشنایی با الگوریتم های لبه یابی، مطلب «الگوریتم های لبه یابی و انواع آن» را مشاهده نمایید.

 

پردازش سیگنال چیست؟

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

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

تاریخچه

با توجه به الن وی. اوپنهایم و رنالد شافر ،اصول اولیه پردازش سیگنال در روش های آنالیز عددی کلاسیک در قرن 17 یافت می شود. اوپنهایم و شافر اشاره کرده اند که “دیجیتالی ساختن” یا پالایش دیجیتالی این روش ها درسیستم های کنترلی در سال های 1940 و 1950 می توان یافت.

 

زمینه های کاربرد

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

در سیستم های ارتباطی پردازش سیگنال ممکن است در زمینه های زیر رخ دهد:

  • مدل اتصال متقابل سامانه های باز، 1 در هفت لایه مدل OSI ، لایه فیزیکی (مدولاسیون،برابر سازی ، هم تافتنو غیره.);
  • OSI لایه 2 لایه پیوند داده ای ;
  • OSI 6، لایه لایه نمایش ( برنامه نویسی از جمله تبدیل آنالوگ به دیجیتالو فشرده سازی سیگنال).

 

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

  • فیلتر – برای مثال آنالوگ (منفعل یا فعال) یا دیجیتال (FIRهای IIR, دامنه فرکانسی یا کنترل تصادفی و غیره.)
  • نمونه برداری و مبدل سیگنال های آنالوگ به دیجیتال برای فراگیری سیگنالها و بازسازی آن ها، که شامل اندازه گیری فیزیکی سیگنال ها،ذخیره سازی یا انتقال آن را به عنوان سیگنال دیجیتال و بازسازی سیگنال اصلی یا تقریبی آن در کاربرد های احتمالی بعدی.
  • فشرده سازی داده ها
  • پردازشگر سیگنال دیجیتال سیگنال دیجیتال (DSPs)

 

روش های ریاضی کاربردی

  • معادلات دیفرانسیل
  • رابطه بازگشتی
  • تئوری تبدیل
  • تجزیه و تحلیل زمان-فرکانس – برای پردازش یگنال های غیر ثابت
  • تخمین طیفی – برای تعیین محتوای طیفی (یعنی توزیع قدرت بر فرکانس) در یک سری زمانی
  • پردازش سیگنال آماری – تجزیه و تحلیل و استخراج اطلاعات از سیگنال و نویز بر اساس خواص اتفاقی
  • نظریه سیستم خطی تغییر ناپذیر با زمان و نظریه تبدیل
  • شناسایی و طبقه بندی سیستم
  • حساب دیفرانسیل و انتگرال
  • فضاهای برداری و جبر خطی
  • آنالیز تابعی
  • احتمال و فرایندهای تصادفی
  • نظریه تشخیص
  • الگوریتم های تخمینی
  • بهینه سازی
  • آنالیز عددی
  • سری های زمانی
  • داده کاوی – برای تجزیه و تحلیل آماری روابط بین مقادیر زیادی از متغیرها (در این زمینه برای نمایش بسیاری از سیگنال های فیزیکی) برای استخراج الگوهای ناشناحته

 

دسته بندی ها

پردازش سیگنال آنالوگ

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

 

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

پردازش سیگنال های پیوسته در زمان برای سیگنال های است که با تغییرات پیوسته دامنه تغییر می کنند(بدون در نظر گرفتن بعضی نقاط منقطع)

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

 

پردازش سیگنال های گسسته در زمان

پردازش سیگنال های گسسته برای سیگنال هایی است که تنها در نقاط گسسته ای از زمان نمونه برداری شده اند ، و در زمان کوانتیده هستند اما در مقدار نه.

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

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

 

پردازش سیگنال دیجیتال

پردازش سیگنال های دیجیتال پردازش نمونه های سیگنال در زمان های گسسته می باشد. پردازش توسط , رایانه ها یا با مدارهای دیجیتال همچون ASIC ها ، field-FPGA ها ،یا پردازنده های سیگنال دیجیتال ها انجام می گیرد . عملیات های معمول ریاضی شامل نمایش نقطه ثابت ، ممیز شناور ، مقدار حقیقی یا مختلط اعداد ، ضرب و جمع از این جمله می باشند. بعضی دیگر از عملیات های معمول توسط دایره بافر و جدول های look-up توسط سخت افزار پشتیبانی می شوند. مثال های از این الگوریتم ها تبدیل فوریه سریع (FFT) ، فیلتر های FIR ، فیلتر های IIR ، و فیلتر تطبیقیمی باشند.

 

غیر خطی پردازش سیگنال های غیرخطی

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

منبع


پردازش سیگنال چیست؟ (Signal processing)

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

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

 

مثال ها

شکل زیر سیگنال صوتی را نشان می‌دهد که هنگام فشار دادن کلید ۱ بر روی تلفن تولید می‌شود:

 

شکل 1-سیگنال پیوسته

 

شکل 2-سیگنال گسسته

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

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

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

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

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

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

 

تبدیل آنالوگ به دیجیتال

دیجیتال کردن سیگنال بر روی سیستم‌های کامپیوتری امروزی توسط کارت‌های صوتی انجام می‌پذیرد. یک سیگنال آنالوگ از لحظه ورود تا دیجیتال شدن مراحل زیر را به ترتیب طی می‌کند:

• آماده کردن سیگنال ورودی
• فیلتر کردن سیگنال ورودی
• نمونه برداری
• چندی کردن
شماتیک زیر نیز فرآیند تبدیل سیگنال آنالوگ به دیجیتال را نشان می‌دهد:

 

آماده کردن سیگنال ورودی

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

در  مراحل بعدی عمل دیجیتال کردن زمانی که از مبدل آنالوگ به دیجیتال استفاده  می‌کنیم، عملا نیاز به ولتاژهایی در بازه ( 5..0) ، ( 5-..5 ) یا … ولت نیاز  داریم. اما  همانطور که دیدیم خروجی برخی از سنسورها ( همانند سنسور نوار قلبی ) در حد  میلی ولت  است. بنابراین نیاز به روشی داریم که بتوانیم خروجی سنسورها را تقویت کرده و  آن‌ها  را برای ورود به مبدل‌های آنالوگ به دیجیتال آماده کنیم.

این  مرحله از عمل دیجیتال کردن ورودی را آماده سازی سیگنال ورودی می‌گوییم که  در آن از  تقویت کننده‌ها ( آمپلی فایر ) برای افزایش/ کاهش بهره ولتاژ استفاده می‌ کنیم. لازم  به ذکر است که امروزه سیستم تقویت کننده سیگنال به شکل توکار بر روی کارت  های صوتی  وجود دارد و در کارهای معمول خود نیاز به نصب تقویت کننده خارجی به کارت  صوتی نداریم.در سیستم عامل ویندوز ضریب بهره آمپلی فایر کارت صوتی توسط Volume Controller خود سیستم عامل تعیین می‌شود.

 

فیلتر کردن سیگنال

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

 

 طراحی فیلترها

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

 

نمونه برداری کردن

پس  از آنکه سیگنال ورودی آماده شد و فیلترکردن آن نیز انجام پذیرفت، دیجیتال  کردن سیگنال آنالوگ آغاز می‌شود. نمونه برداری بدین مفهوم است که در بازه‌های  زمانی مشخص مقدار سیگنال ورودی را خوانده و برای چندی شدن به مرحله بعد انتقال دهیم.  به عنوان مثال  زمانی که می‌خواهیم در هر ثانیه 44000 نمونه از سیگنال ورودی برداریم،  باید در بازه  های زمانی 0.00002 ثانیه مقدار سیگنال آنالوگ را خوانده و به مرحله بعد  منتقل کنیم. به عنوان مثال زمانی که در میکروفون صحبت می‌کنید، با فرض اینکه نرخ  نمونه برداری 44000 نمونه در ثانیه باشد، سیستم دیجیتال کننده هر 0.00002 ثانیه  یکبار ولتاز خروجی میکروفون را – که تقویت و فیلتر شده است – خوانده و مقدار آن  را به چندی  کننده ارسال می‌کند.

 

چندی کردن سیگنال

در  مرحله نمونه برداری دیدیم که یک نمونه از سیگنال به شکل ولتاژ نمونه برداری  شد. در  این مرحله ولتاز نمونه برداری شده باید به شکل دیجیتالی ( عدد باینری )  تبدیل شود.  برای این منظور نیز از مبدل‌های آنالوگ به دیجیتال استفاده می‌کنیم. به  عنوان مثال  یک مبدل انالوگ به دیجیتال 8 بیتی به ازای ورودی خود عددی بین 0 تا 255  تولید می‌ کند. فرض کنید ورودی مبدل در بازه 0 تا 5 ولت باشد. این بدان معناست که به  ازای ورودی 0 ولت ، خروجی مبدل عدد باینری 0 و به ازای ورودی 5 ولت خروجی مبدل  عدد باینری 255 خواهد بود. بدیهی است که افزایش تعداد بیت‌های مبدل موجب افزایش  دقت چندی  شدن خواهد شد.

 

مقدمه

فراتفکیک پذیری (Super resolution)- سیستم‌های تصویربرداری دیجیتال به دلیل راحتی کاربرد و هزینه مناسب بطور چشمگیری گسترش یافته‌اند، اما هنوز به دلیل پائین بودن رزولوشن (تفکیک پذیری یا وضوح تصویری) نسبت به سیستم‌های تصویر برداری پیشین (سیستم‌های نوری)، دچار ضعف می‌باشند. تلاش‌های بسیاری جهت افزایش رزولوشن تصاویر دیجیتالی صورت گرفته که به دو بخش کلی نرم‌افزاری و سخت‌افزاری قابل تقسیم بندی می‌باشند.

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

بنابراین روش سخت‌افزاری جهت رسیدن به تصاویری با کیفیت و رزولوشن بالاتر، بسیار پرهزینه و عملاً تا حدی غیر ممکن می‌باشد و معمولاً نمی‌توان از حد معینی، بدلیل محدودیت‌های تکنیکی موجود در تکنولوژی ساخت مدارات مجتمع، فراتر رفت.

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

 

فراتفکیک پذیری

این تکنیک از لحاظ نامگذاری بدلیل آنکه قادر خواهیم بود از محدوده توانایی سیستم تصویر برداری فراتر رویم، فرا تفکیک پذیری نامیده می‌شود؛ در این تکنیک تلفیق چندین تصویر با رزولوشن پائین تر باعث تولید تصویر نهایی با رزولوشن بالاتر می‌گردد. نکته کلیدی در این تکنیک، استفاده از در هم آمیختگی می‌باشد زیرا که هر تصویر برداشت شده از صحنه مورد نظر تنها بخشی از اطلاعات فرکانس بالای صحنه را دریافت نموده‌است و این اطلاعات فرکانس بالا در تمام تصاویر پخش شده‌است، بنابراین می‌توان از این اطلاعات توزیع شده استفاده نمود و تصویری با رزولوشن و کیفیت بالاتر ایجاد نمود. مطالعات انجام شده نشان می‌دهد که پدیده در هم آمیختگی به دلیل محدود بودن تعداد پیکسل هایِ حسگر هایِ دوربین هایِ دیجیتالی می‌باشد.
فراتفکیک پذیری، چرا و چه وقت ممکن می‌باشد؟ [ویرایش]

سوال بنیادی این می‌باشد که چه عاملی فراتفکیک پذیری را ممکن می‌سازد. این پرسش را توسط مثالی که در ادامه بدان خواهیم پرداخت، توضیح خواهیم داد؛ چنانچه حسگر دوربینی با ابعاد ۴*۴ از صحنه خاصی تصویر برداری نماید، با افزایش تعداد سلول‌های حسگر دوربین به تعداد ۱۶*۱۶، تصویر برداشت شده دارای رزولوشن بیشتری خواهد بود. حال اگر توسط همان حسگر چهار تصویر از یک صحنه یکسان برداشت نمائیم که اختلاف آنها در حد مقداری صحیح از واحد پیکسل باشد، فراتفکیک پذیری ممکن نخواهد بود، ولی چنانچه چهار تصویر دریافتی اختلافی در حد کسری از واحد پیکسل داشته باشند، فراتفکیک پذیری ممکن می‌گردد؛ زیرا که اختلاف چهار تصویر فوق در حد کسری از واحد پیکسل، اطلاعات اضافه‌ای را از صحنه برداشت شده ایجاب می‌کند که پتانسیل افزایش رزولوشن را تقویت می‌نماید.

 

پیکربندی تکنیک فراتفکیک پذیری

اکثر روش‌های فراتفکیک پذیری را می‌توان به دو بخش تقسیم نمود: بخش ثبت تصویر Image Registration و بخش بازسازی تصویر Image Reconstruction. دقت بسیار بالایی در بخش ثبت تصویر لازم است (در حد کسری از واحد پیکسل) تا بتوان در بخش بازسازی، تصویری با رزولوشن بالا را بطور صحیح ایجاد نمود. اگر پارامترهای ثبت تصویر بطور غلط تخمین زده شده باشند، معمولاً بهتر است که یکی از تصاویر را توسط روش‌های درونیابی به اندازه مطلوب تغییر دهیم، تا اینکه اطلاعات چندین تصویر را بطور غلط، با یکدیگر تلفیق نمائیم.

پس از آنکه تصاویر ثبت شدند، جهت بدست آوردن تصویری با رزولوشن بالا از نمونه‌های نمونه برداری شده بصورت غیریکنواخت، یک روش بازسازی تاثیر ناپذیر از نویز (Robust)، لازم می‌باشد. بخش اصلی تر، بخش ثبت تصویر می‌باشد که در تکنیک فراتفکیک پذیری از اهمیت بالایی برخوردار می‌باشد، زیرا که در این بخش تفاوت اصلی میان درونیابی و تکنیک فراتفکیک پذیری بطور آشکار مشخص می‌شود.

[عکس: Super-resolution_example_closeup.png]ت
تصویر سمت چپ تصویر اصلی و تصویر سمت راست تصویر بعد از فراتفکیک‌پذیری است

 

چرا دوربین‌ها 29.97 فریم بر ثانیه فیلم‌برداری می‌کنند و نه 30 فریم؟

چرا در جزییات فنی فیلم‌برداری در بخش فریم ریت به جای عدد ۳۰ فریم، عدد29.97 فریم بر ثانیه فیلم‌برداری ذکر می‌شود؟ احتمالاً اگر در بررسی مشخصات ویدیویی خیلی از دوربین‌ها از دوربین‌های موبایل گرفته تا دوربین‌های فیلم‌برداری، نکته‌سنج بوده باشید این سؤال در ذهن شما هم شکل گرفته باشد. هر چند که می‌توان این مطلب را به صورت فنی تشریح کرد ولی در ادامه سعی شده است تا با بیانی ساده آن را موردبررسی قرار دهیم.در ابتدا بهتر است ، کمی راجع به فریم ریت توضیح بدهیم. فریم ریت یا در اصل همان فریم در ثانیه به نرخ تصویری اشاره دارد که به صورت متوالی و پشت سر هم توسط یک دستگاه تولید می‌شود.

واحد اندازه‌گیری فریم،FPS یا همان فریم در ثانیه است. برای همین وقتی در مشخصات فیلم‌برداری دوربین عدد ۲۹٫۹۷ درج می‌شود این عدد معادل تعداد فریم هایی است که آن دوربین در عرض یک ثانیه ثبت می‌کند. حتی در دوربین‌های پیشرفته‌تر که به ادعای شرکت سازنده می‌توانند تصاویر را با فریم ریت 60 fps رکورد کنند در ۹۹ درصد مواقع در هر دو حالت DF و NDF به صورت دقیق با فریم ریت ۵۹.۹۴ فریم بر ثانیه تصاویر را ضبط می‌کند. با این تفاسیر چرا این عدد دقیقاً ۳۰ یا ۶۰ فریم در ثانیه نیست؟

مروری بر گذشته

در زمان معرفی اولین تلویزیون‌های سیاه و سفید NTSC فریم ریت دقیقاً معادل ۳۰ فریم در ثانیه بود؛ اما رد پای عدد عجیب ۲۹٫۹۷ و (بعدها ۵۹.۹۴) فریم در ثانیه برای اولین بار با معرفی تلویزیون‌های رنگی پیدا شد. در زمان تولید این تلویزیون‌ها، مهندسان سازنده باید اطلاعات رنگ را نیز به سیگنال‌های تلویزیونی اضافه می‌کردند؛ اما به خاطر محدودیت پهنای باند تصمیم گرفتند که تا حد ناچیزی از فریم ریت تلویزیون بکاهند تا اطلاعات رنگ نیز بدون اینکه سیگنال‌های تلویزیونی دچار معایبی شوند در آن گنجانده شود.

 

 

این تصمیم از این جهت گرفته شد که عملاً چاره دیگری نبود، از نظر فنی امکان افزایش پهنای باند وجود نداشت؛ و افزایش تفکیک‌پذیری (بالا بردن تعداد خط‌های افقی) بدون افزایش پهنای باند درنهایت باعث افت تفکیک‌پذیری و کاهش کیفیت تصویر می‌شد. برای همین 29.97 فریم در ثانیه به فریم ریت استاندارد تلویزیون‌های رنگی NTSC تبدیل شد. دوربین‌های فیلم‌برداری امروزی هم به همان ترتیب به جای 30 فریم در واقع قابلیت ثبت 29.97 فریم در ثانیه را دارند. البته این تفاوت آن‌قدر ناچیز هست که در اصطلاح رایج به ذکر عدد 30 و 60 فریم در ثانیه اکتفا می‌شود.

 

 

از طرفی دیگر استاندارد تلویزیونی PAL کاملاً برای سازگاری با تلویزیون‌های رنگی در نظر گرفته شده است. در نتیجه بدون لطمه خوردن به تفکیک‌پذیری، از فریم ریتی مناسبی برخوردار است؛ بنابراین بستگی دارد که دوربین با چه استانداردی (PAL و NTSC) تصاویر را رکورد می‌کند.

 

 

Interpolation يا درون یابی

Interpolation يا درون یابی (كه گاهي resampling نيز ناميده ‌مي‌شود) يك روش گرافيكي براي افزايش يا كاهش تعداد پيكسل‌هاي يك تصوير ديجيتالي است. دوربين‌هاي ديجيتالي از اين روش براي زوم ديجيتال و يا افزايش مصنوعي ابعاد تصوير، نسبت به تصوير اصلي ثبت شده توسط حسگر خود استفاده مي‌كنند. كيفيت تصوير نهايي حاصل از درون‌يابي به پيچيدگي الگوريتم ساخت تصوير بستگي دارد. حالت‌هاي متفاوت درون‌يابي عبارتند است از:

Nearest Neighbor Interpolation

اين روش ساده‌ترين عمليات درون‌يابي محسوب مي‌شود كه اساساً پيكسل‌هاي بزرگ‌تري را ايجاد مي‌كند و رنگ هر پيكسل در تصوير جديد، با رنگ نزديك‌ترين پيكسل در تصوير اصلي مطابقت دارد. به عنوان مثال اگر شما يك تصوير را 200 درصد بزرگ كنيد، يك پيكسل تصوير به يك فضاي چهار پيكسلي (دو پيكسل در دو پيكسل) با رنگ پيكسل اوليه تبديل مي‌شود. بسياري از دوربين‌هاي ديجيتالي براي زوم‌كردن روي يك سوژه از اين روش استفاده مي‌كنند. زيرا اين روش هيچ تأثيري بر اطلاعات رنگي تصوير نمي‌گذارد. اصولاً بهتر است از اين روش براي افزايش ابعاد تصوير استفاده نشود. چرا كه موجب ايجاد حالت شطرنجي در تصوير مي‌گردد.

Bilinear Interpolation

اين روش ارزش يك پيكسل رنگي را براساس چهار پيكسل در جهت‌هاي عمودي و افقي پيكسل در تصوير اصلي معين‌مي‌كند. تصوير جديد داراي خاصيت Anti-aliasing است و تقريباً هيچ اثري از پيكسل‌هاي شطرنجي در آن ديده نمي‌شود.

Bicubic Interpolation

اين روش داراي پيچيده‌ترين الگوريتم درون‌يابي است و تصويري كه با اين روش به دست مي‌آيد، لبه‌هاي بسيارنرم‌تري پيدا مي‌كند. در اين حالت پيكسل جديد براساس ارزش تخميني 16 پيكسل (چهار پيكسل در چهار پيكسل) برآورد‌مي‌شود.

شايان ذكر است كه اغلب دوربين‌ها، چاپگرها و نرم‌افزارهاي گرافيكي براي تغيير تعداد پيكسل‌هاي يك تصوير از اين روش استفاده مي‌كنند.
نرم‌افزار Photoshop CS دو نوع Sharper و Smoother اين درون‌يابي را نيز ارائه مي‌دهد.

Fractal Interpolation

اين روش براي بزرگ كردن تصوير در ابعاد خيلي بزرگ (به‌عنوان مثال چاپ روي بدنه يك اتوبوس) روش بسيار مناسبي به‌شمار مي‌رود. زيرا با دقت خوبي مي‌تواند شكل اجزاي تصوير را حفظ كند. لبه‌هاي بسيار تميزتر و صاف‌تري را نيز برجا مي‌گذارد. در اين حالت مناطق محوي كه در لبه‌هاي تصوير در روش‌هاي قبل وجود داشتند، به ندرت ديده مي‌شوند. البته روش‌هاي ديگري هم وجود دارند كه جز در برنامه‌هاي گرافيكي پيشرفته، به‌ندرت از آن‌ها استفاده مي‌شود.