بایگانی برچسب برای: fishk hknda
استفاده از متد WhenAll برای اجرای چندین Task به صورت همزمان در سی شارپ
فرض کنید که داخل یک متد باید چندین متد را به صورت await فراخوانی کنید. به صورت عادی زمانی که متدها فراخوانی می شوند هر بخش await بعد از تکمیل await قبلی اجرا خواهد شد و مقادیر بازگشتی به صورت یکجا در اختیار شما قرار نمیگیرند. برای مثال، کد زیر را در نظر بگیرید:
private async void AsyncBtn_Click(object sender, EventArgs e) { Result1TextBox.Text = (await Task1()).ToString(); Result12extBox.Text = (await Task2()).ToString(); } private Task < long > Task1() { return Task.Run<long>(() = > { var num = Enumerable.Repeat(10, 1000); long sum = 0; foreach (var item in num) { System.Threading.Thread.Sleep(2); sum += item; } return sum; }); } private Task < long > Task2() { return Task.Run<long>(() = > { var num = Enumerable.Repeat(10, 1000); long sum = 0; foreach (var item in num) { System.Threading.Thread.Sleep(2); sum += item; } return sum; }); }
در کد بالا، ابتدا عملیات Task1 انجام شده و نتیجه نمایش داده می شود و پس از آن Task2 اجرا شده و نتیجه نمایش داده می شود. برای رفع وقفه بین اجرای دو Task از متد WhenAll استفاده می کنیم. برای استفاده از متد WhenAll کد BtnAsync_Click را به صورت زیر تغییر می دهیم:
private async void AsyncBtn_Click(object sender, EventArgs e) { var results = await Task.WhenAll(Task1(), Task2()); txtBox.Text = results[0].ToString(); txtSecond.Text = results[1].ToString(); }
با ایجاد تغییر کد بالا، خروجی متد WhenAll یک آرایه از نوع long خواهد بود که هر یک از اندیس های آرایه به ترتیب خروجی متدهای اول و دوم می باشد و به صورت بالا می توان خروجی ها را در TextBox ها نمایش داد.
منبع
قسمت اول آموزش-برنامه نویسی 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 به صورت همزمان در سی شارپ
الگوریتم Canny
لبه یاب کنی توسط جان اف کنی در سال 1986 ایجاد شد و هنوز یک لبه یاب استاندارد و با دقت و کیفیت بالا میباشد.الگوریتم لبه یابی کنی یکی از بهترین لبه یابها تا به امروز است. در ادامه روش کار این الگوریتم و هم چنین کد الگوریتم Canny در C را بررسی خواهیم کرد. این الگوریتم لبه یابی از سه بخش اصلی زیر تشکیل شده است:
- تضعیف نویز
- پیدا کردن نقاطی که بتوان آنها را به عنوان لبه در نظر گرفت
- جذب نقاطی که احتمال لبه بودن آنها کم است
معیارهایی که در لبه یاب کنی مطرح می باشد:
1 -پایین آوردن نرخ خطا- یعنی تا حد امکان هیچ لبه ای در تصویر نباید گم شود و هم چنین هیچ چیزی که لبه نیست نباید به جای لبه فرض شود. لبه هان پیدا شده تا حد ممکن به لبه ها اصلی
نزدیک باشند.
2 -لبه در مکان واقعی خود باشد- یعنی تا حد ممکن لبه ها کمترین فاصله را با مکان واقعی خود داشته باشند.
3 -بران هر لبه فقط یک پاسخ داشته باشیم.
4 -لبه ها کمترین ضخامت را داشته باشند- (در صورت امکان یک پیکسل).
لبه یاب کنی بخاطر توانایی در تولید لبه های نازک تا حد یک ییکسل برای لبه های پیوسته معروف شده است. این لبه یاب شامل چهار مرحله و چهار ورودی زیر است:
یک تصویر ورودی
یک پارامتر به نام سیگما جهت مقدار نرم کنندگی تصویر
یک حد آستانه بالا (Th)
یک حد آستانه پایین (Tl)
مراحل الگوریتم Canny:
1- در ابتدا باید تصویر رنگی را به جهت لبه یابی بهتر به یک تصویر سطح خاکسترن تبدیب کرد.
2- نویز را از تصویر دریافتی حذف کرد. بدلیل اینکه فیلتر گاوسین از یک ماسک ساده برای حذف نویز استفاده می کند لبه یاب کنی در مرحله اول برای حذف نویز آن را بکار می گیرد.
3- در یک تصویر سطح خاکستر جایی را که بیشترین تغییرات را داشته باشند به عنوان لبه در نظر گرفته می شوند و این مکانها با گرفتن گرادیان تصویر با استفاده عملگر سوبل بدست می آیند. سپس لبه های مات یافت شده به لبه های تیزتر تبدیل می شوند.
4- برخی از لبه های کشف شده واقعا لبه نیستند و در واقع نویز هستند که باید آنها توسط حد آستانه هیسترزیس فیلتر شوند.هیسترزیس از دو حد آستانه بالاتر (Th) و حد آستانه پایین تر (Tl) استفاده کرده و کنی پیشنهاد می کند که نسبت استانه بالا به پایین سه به یک باشد.
این روش بیشتر به کشف لبه های ضعیف به درستی می پردازد و کمتر فریب نویز را می خورد و از بقیه روش ها بهتر است.
کد الگوریتم 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 در Visual Basic را بررسی خواهیم کرد. این الگوریتم لبه یابی از سه بخش اصلی زیر تشکیل شده:
- تضعیف نویز
- پیدا کردن نقاطی که بتوان آنها را به عنوان لبه در نظر گرفت
- حذب نقاطی که احتمال لبه بودن آنها کم است
معیارهایی که در لبه یا کنی مطرح است:
1 -پایین آوردن نرخ خطا- یعنی تا حد امکان هیچ لبه ای در تصویر نباید گم شود و هم چنین هیچ چیزی که لبه نیست نباید به جای لبه فرض شود. لبه هان پیدا شده تا حد ممکن به لبه ها اصلی
نزدیک باشند.
2 -لبه در مکان واقعی خود باشد- یعنی تا حد ممکن لبه ها کمترین فاصله را با مکان واقعی خود داشته باشند.
3 -بران هر لبه فقط یک پاسخ داشته باشیم.
4 -لبه ها کمترین ضخامت را داشته باشند- (در صورت امکان یک پیکسل).
لبه یاب کنی بخاطر توانایی در تولید لبه های نازک تا حد یک ییکسل برای لبه های پیوسته معروف شده است. این لبه یاب شامل چهار مرحله و چهار ورودی زیر است:
یک تصویر ورودی
یک پارامتر به نام سیگما جهت مقدار نرم کنندگی تصویر
یک حد آستانه بالا (Th)
یک حد آستانه پایین (Tl)
مراحل الگوریتم Canny:
1- در ابتدا باید تصویر رنگی را به جهت لبه یابی بهتر به یک تصویر سطح خاکسترن تبدیب کرد.
2- نویز را از تصویر دریافتی حذف کرد. بدلیل اینکه فیلتر گاوسین از یک ماسک ساده برای حذف نویز استفاده می کند لبه یاب کنی در مرحله اول برای حذف نویز آن را بکار میگیرد.
3- در یک تصویر سطح خاکستر جایی را که بیشترین تغییرات را داشته باشند به عنوان لبه در نظر گرفته می شوند و این مکانها با گرفتن گرادیان تصویر با استفاده عملگر سوبل بدست می آیند. سپس لبه های مات یافت شده به لبه های تیزتر تبدیل می شوند.
4- برخی از لبه های کشف شده واقعا لبه نیستند و در واقع نویز هستند که باید آنها توسط حد آستانه هیسترزیس فیلتر شوند.هیسترزیس از دو حد آستانه بالاتر (Th) و حد آستانه پایین تر (Tl) استفاده کرده و کنی پیشنهاد می کند که نسبت استانه بالا به پایین سه به یک باشد.
این روش بیشتر به کشف لبه های ضعیف به درستی می پردازد و کمتر فریب نویز را می خورد و از بقیه روش ها بهتر است.
الگوریتم Canny در Visual Basic:
کد زیر یک کد تکمیل نشده است.تکمیل آن به عنوان تمرین به خواننده واگذار می شود.
Imports System.Drawing Imports System.Drawing.Imaging Public Class clsEdges Public Sub EdgeDetectDifference(ByVal b As Bitmap, ByVal threshold As Byte) ' first we create a clone o the image we want to find the edges on Dim b2 As Bitmap = b.Clone ' we create bitmapdata of the images at the same time locking them Dim bmData1 As BitmapData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb) Dim bmData2 As BitmapData = b2.LockBits(New Rectangle(0, 0, b2.Width, b2.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb) ' the stride describes the distance between image bytes Dim stride As Integer = bmData2.Stride ' scan0 is some sort of OS handle or something to identify the actual data in the memory Dim scan01 As IntPtr = bmData1.Scan0 Dim scan02 As IntPtr = bmData2.Scan0 ' we need to know how big the data is so that we can create the correct size for the file Dim bytes As Integer = b.Height * b.Width * 3 ' we create the byte arrays so that we can edit them Dim p01(bytes - 1) As Byte Dim p02(bytes - 1) As Byte ' put the images into the byte arrays System.Runtime.InteropServices.Marshal.Copy(scan01, p01, 0, bytes) System.Runtime.InteropServices.Marshal.Copy(scan02, p02, 0, bytes) ' the nWidth describes the width of the actual image multiplied by three for each byte in the pixel (3 bytes per pixel 24 bits ;)) Dim nWidth As Integer = b2.Width * 3 ' for some reason although the original code show a formula to come up with the offset this doesn't work very well. ' I found that it is just easier to make the offset 0 and so all bits are handled. Basically the problem comes when ' using this on files that don't have Dim nOffset As Integer = 0 Dim nPixel As Integer = 0, npixelmax As Integer = 0 Dim pos1 As Integer = stride + 3 Dim pos2 As Integer = stride + 3 Dim p2minusplus As Integer, p2plusminus As Integer, p2plusplus As Integer, p2minusminus As Integer Dim p2minusstride As Integer, p2plusstride As Integer Dim p2plus As Integer, p2minus As Integer For y As Integer = 1 To b.Height - 1 For x As Integer = 1 To nWidth - 3 p2minusplus = pos2 - stride + 3 p2plusminus = pos2 + stride - 3 p2plusplus = pos2 + stride + 3 p2minusminus = pos2 - stride - 3 p2minusstride = pos2 - stride p2plusstride = pos2 + stride p2minus = pos2 - 3 p2plus = pos2 + 3 If p2minusplus <= p02.Length - 1 And p2minusplus >= 0 And p2plusminus <= p02.Length - 1 And p2plusminus >= 0 And _ p2plusplus <= p02.Length - 1 And p2plusplus >= 0 And p2minusminus <= p02.Length - 1 And p2minusminus >= 0 And _ p2minusstride <= p02.Length - 1 And p2minusstride >= 0 And p2plusstride <= p02.Length - 1 And p2plusstride >= 0 And _ p2plus <= p02.Length - 1 And p2plus >= 0 And p2minus <= p02.Length - 1 And p2minus >= 0 And pos1 < p01.Length Then npixelmax = Math.Abs(CInt(p02(p2minusplus)) - CInt(p02(p2plusminus))) nPixel = Math.Abs(CInt(p02(p2plusplus)) - CInt(p02(p2minusminus))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(p2minusstride)) - CInt(p02(p2plusstride))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(p2plus)) - CInt(p02(p2minus))) If nPixel > npixelmax Then npixelmax = nPixel If npixelmax < CInt(threshold) Then npixelmax = 0 p01(pos1) = CByte(npixelmax) End If pos1 += 1 pos2 += 1 Next pos1 += nOffset pos2 += nOffset Next System.Runtime.InteropServices.Marshal.Copy(p01, 0, scan01, bytes) b.UnlockBits(bmData1) b2.UnlockBits(bmData2) End Sub Public Sub EdgeDetectHomogenity(ByVal b As Bitmap, ByVal threshold As Byte) Dim b2 As Bitmap = b.Clone Dim bmData1 As BitmapData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb) Dim bmData2 As BitmapData = b2.LockBits(New Rectangle(0, 0, b2.Width, b2.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb) Dim stride As Integer = bmData2.Stride Dim scan01 As IntPtr = bmData1.Scan0 Dim scan02 As IntPtr = bmData2.Scan0 Dim bytes As Integer = b.Height * b.Width * 3 Dim p01(bytes - 1) As Byte Dim p02(bytes - 1) As Byte System.Runtime.InteropServices.Marshal.Copy(scan01, p01, 0, bytes) System.Runtime.InteropServices.Marshal.Copy(scan02, p02, 0, bytes) Dim nWidth As Integer = b2.Width * 3 Dim nOffset As Integer = 0 Dim nPixel As Integer = 0, npixelmax As Integer = 0 Dim pos1 As Integer = stride + 3 Dim pos2 As Integer = stride + 3 Dim p2plusminus As Integer, p2plusstride As Integer, p2plusplus As Integer, p2minusstride As Integer, _ p2minusminus As Integer, p2minusplus As Integer For y As Integer = 1 To b.Height - 1 For x As Integer = 1 To nWidth - 3 p2plusminus = pos2 + stride - 3 p2plusstride = pos2 + stride p2plusplus = pos2 + stride + 3 p2minusstride = pos2 - stride p2minusminus = pos2 - stride - 3 p2minusplus = pos2 - stride + 3 If p2plusminus < p02.Length And p2plusminus >= 0 And p2plusstride < p02.Length And p2plusstride >= 0 And _ p2plusplus < p02.Length And p2plusplus >= 0 And p2minusstride < p02.Length And p2minusstride >= 0 And _ p2minusstride < p02.Length And p2minusstride >= 0 And p2minusminus < p02.Length And p2minusminus >= 0 And _ p2minusplus < p02.Length And p2minusplus >= 0 Then npixelmax = Math.Abs(CInt(p02(pos2)) - CInt(p02(p2plusminus))) nPixel = Math.Abs(CInt(p02(pos2)) - CInt(p02(p2plusstride))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(pos2)) - CInt(p02(p2plusplus))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(pos2)) - CInt(p02(p2minusstride))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(pos2)) - CInt(p02(p2plusstride))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(pos2)) - CInt(p02(p2minusminus))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(pos2)) - CInt(p02(p2minusstride))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(pos2)) - CInt(p02(p2minusplus))) If nPixel > npixelmax Then npixelmax = nPixel If npixelmax < threshold Then npixelmax = 0 p01(pos1) = CByte(npixelmax) End If pos1 += 1 pos2 += 1 Next pos1 += nOffset pos2 += nOffset Next System.Runtime.InteropServices.Marshal.Copy(p01, 0, scan01, bytes) b.UnlockBits(bmData1) b2.UnlockBits(bmData2) End Sub Public Function EdgeEnhance(ByVal b As Bitmap, ByVal threshold As Byte) As Boolean Dim b2 As Bitmap = b.Clone Dim bmData1 As BitmapData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb) Dim bmData2 As BitmapData = b2.LockBits(New Rectangle(0, 0, b2.Width, b2.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb) Dim stride As Integer = bmData2.Stride Dim scan01 As IntPtr = bmData1.Scan0 Dim scan02 As IntPtr = bmData2.Scan0 Dim bytes As Integer = b.Height * b.Width * 3 Dim p01(bytes - 1) As Byte Dim p02(bytes - 1) As Byte System.Runtime.InteropServices.Marshal.Copy(scan01, p01, 0, bytes) System.Runtime.InteropServices.Marshal.Copy(scan02, p02, 0, bytes) Dim nWidth As Integer = b2.Width * 3 Dim nOffset As Integer = 0 Dim nPixel As Integer = 0, npixelmax As Integer = 0 Dim pos1 As Integer = stride + 3 Dim pos2 As Integer = stride + 3 Dim p2minusplus As Integer, p2plusminus As Integer, p2plusplus As Integer, p2minusminus As Integer Dim p2minusstride As Integer, p2plusstride As Integer Dim p2plus As Integer, p2minus As Integer For y As Integer = 1 To b.Height - 1 For x As Integer = 1 To nWidth - 3 p2minusplus = pos2 - stride + 3 p2plusminus = pos2 + stride - 3 p2plusplus = pos2 + stride + 3 p2minusminus = pos2 - stride - 3 p2minusstride = pos2 - stride p2plusstride = pos2 + stride p2minus = pos2 - 3 p2plus = pos2 + 3 If p2minusplus <= p02.Length - 1 And p2minusplus >= 0 And p2plusminus <= p02.Length - 1 And p2plusminus >= 0 And _ p2plusplus <= p02.Length - 1 And p2plusplus >= 0 And p2minusminus <= p02.Length - 1 And p2minusminus >= 0 And _ p2minusstride <= p02.Length - 1 And p2minusstride >= 0 And p2plusstride <= p02.Length - 1 And p2plusstride >= 0 And _ p2plus <= p02.Length - 1 And p2plus >= 0 And p2minus <= p02.Length - 1 And p2minus >= 0 And pos1 < p01.Length Then npixelmax = Math.Abs(CInt(p02(pos2 - stride + 3)) - CInt(p02(pos2 + stride - 3))) nPixel = Math.Abs(CInt(p02(pos2 + stride + 3)) - CInt(p02(pos2 - stride - 3))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(pos2 - stride)) - CInt(p02(pos2 + stride))) If nPixel > npixelmax Then npixelmax = nPixel nPixel = Math.Abs(CInt(p02(pos2 + 3)) - CInt(p02(pos2 - 3))) If nPixel > npixelmax Then npixelmax = nPixel If npixelmax > threshold And npixelmax > p01(pos1) Then p01(pos1) = CByte(Math.Max(CInt(p01(pos1)), npixelmax)) End If End If pos1 += 1 pos2 += 1 Next pos1 += nOffset pos2 += nOffset Next System.Runtime.InteropServices.Marshal.Copy(p01, 0, scan01, bytes) b.UnlockBits(bmData1) b2.UnlockBits(bmData2) Return True End Function End Class
این کد کامل نیست!
دانلود کد فوق از طریق لینک زیر:
CannyInVisualBasic
رمز فایل : behsanandish.com
مقدمه
الگوریتم های لبه یابی- انسان مي تواند بسیاري از اشیاء را از روي تصویر خطوط آنها شناسایي كند. بهترین مثال برای آن تصاویر کارتنی است. سیستم بینایي انسان قبل از بازشناسي رنگ یا شدت روشنایي نوعی كشف لبه انجام مي دهد. بنابراین انجام كشف لبه قبل از تفسیر تصاویر در سیستمهاي خودكار منطقي به نظر مي رسد. انجام عملیات كشف لبه پردازش مهمي در بسیاري از سیستمهاي بینایي مصنوعي محسوب مي شود. هدف اصلی لبه یابی کاهش حجم داده ها در تصویر به همراه حفظ ساختار و شکل اصلی تصویر است. مرزماند سایه یک واقعیت فیزیکی نیست و عبارت است از جایی که بخشی از تصویر شروع یا تمام میشود. لبه را میتوان به عنوان جایی که صفحات افقی و عمودی جسم به هم میرسند در نظر گرفت.
یکی از متداولترین اعمال در تحلیل تصویر تشخیص لبه می باشد به این دلیل که لبه مرز میان یک شی و زمینهء آن است به عبارت دیگر لبه تغییر دو سطح خاکستري یا مقادیر مربوط به روشنایی دو پیکسل مجاور است که در مکان خاصی از تصویر رخ می دهد.هر چه این تغییر در سطح بیشتر باشد تشخیص لبه ساده تر خواهد بود.
نقاطي از تصویر كه داراي تغییرات روشنایي ناگھاني ھستند اغلب لبه یا نقاط لبه نامیده مي شوند. نقاط لبه معمولا ً شامل مرزھاي اشیاء و دیگر انواع تغییرات روشنایي و ھمچنین لبه ھاي نویزي مي باشند.
انواع لبه:
انواع الگوریتم های لبه یابی
1- الگوریتم soble
این متد لبه ها را با استفاده از تخمین زدن مشتق پیدا می کند، که لبه ها را در آن نقاطی بر می گرداند که گرادیان تصویر I ، max است. در فیلتر سوبل دو ماسک به صورت زیر وجود دارد:
ماسک سوبل افقی بیشتر لبه هاي افقی را مشخص میکند و ماسک سوبل عمودي،لبه هاي عمودي را مشخص میکند.
براي مشخص شدن کلیه لبه ها:
اگر Gx و 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)<1 Dx(i,j)=0; else Dx(i,j)=1; end if Dy(i,j)<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)<1) S(i,j)=0; else S(i,j)=1; end end end
الگوریتم سوبل به زبان متلب
رمز فایل : behsanandish.com
2- الگوریتم Canny
لبه یاب کنی توسط جان اف کنی در سال 1986 ایجدداد شد و هنوز یک لبه یاب استاندارد و با دقت و کیفیت بالا میباشد.الگوریتم لبه یابی کنی یکی از بهترین لبه یابها تا به امروز است. این الگوریتم لبه یابی از سه بخش اصلی زیر تشکیل شده است:
- تضعیف نویز
- پیدا کردن نقاطی که بتوان آنها را به عنوان لبه در نظر گرفت
- حذب نقاطی که احتمال لبه بودن آنها کم است
معیارهایی که در لبه یا کنی مطرح است:
1 -پایین آوردن نرخ خطا- یعنی تا حد امکان هیچ لبه ای در تصویر نباید گم شود و هم چنین هیچ چیزی که لبه نیست نباید به جای لبه فرض شود. لبه هان پیدا شده تا حد ممکن به لبه ها اصلی
نزدیک باشند.
2 -لبه در مکان واقعی خود باشد- یعنی تا حد ممکن لبه ها کمترین فاصله را با مکان واقعی خود داشته باشند.
3 -بران هر لبه فقط یک پاسخ داشته باشیم.
4 -لبه ها کمترین ضخامت را داشته باشند- (در صورت امکان یک پیکسل).
لبه یاب کنی بخاطر توانایی در تولید لبه های نازک تا حد یک ییکسل برای لبه های پیوسته معروف شده است. این لبه یاب شامل چهار مرحله و چهار ورودی زیر است:
یک تصویر ورودی
یک پارامتر به نام سیگما جهت مقدار نرم کنندگی تصویر
یک حد آستانه بالا (Th)
یک حد آستانه پایین (Tl)
و مراحل شامل
1- در ابتدا باید تصویر رنگی را به جهت لبه یابی بهتر به یک تصویر سطح خاکسترن تبدیب کرد.
2- نویز را از تصویر دریافتی حذف کرد. بدلیل اینکه فیلتر گاوسین از یک ماسک ساده برای حذف نویز استفاده می کند لبه یاب کنی در مرحله اول برای حذف نویز آن را بکار میگیرد.
3- در یک تصویر سطح خاکستر جایی را که بیشترین تغییرات را داشته باشند به عنوان لبه در نظر گرفته می شوند و این مکانها با گرفتن گرادیان تصویر با استفاده عملگر سوبل بدست می آیند. سپس لبه های مات یافت شده به لبه های تیزتر تبدیل می شوند.
4- برخی از لبه های کشف شده واقعا لبه نیستند و در واقع نویز هستند که باید آنها توسط حد آستانه هیسترزیس فیلتر شوند.هیسترزیس از دو حد آستانه بالاتر (Th) و حد آستانه پایین تر (Tl) استفاده کرده و کنی پیشنهاد می کند که نسبت استانه بالا به پایین سه به یک باشد.
این روش بیشتر به کشف لبه های ضعیف به درستی می پردازد و کمتر فریب نویز را می خورد و از بقیه روش ها بهتر است.
clear; clc; close all; warning off; I=imread('siahosefid.bmp'); I=imnoise(I, 'gaussian', 0, 0.001); figure(1) imshow(I); A=filter2(fspecial('average',3),I)/255; figure(2) imshow(A); gauss_I=I; Isize=size(I); ans=zeros(size(I)); dir=zeros(size(I)); I=double(I); gauss_I=double(gauss_I); fx=0; fy=0; for i=2:Isize(1)-1 for j=2:Isize(2)-1 fx=gauss_I(i,j)+gauss_I(i,j+1)-gauss_I(i+1,j)-gauss_I(i+1,j+1); fy=gauss_I(i,j)+gauss_I(i+1,j)-gauss_I(i,j+1)-gauss_I(i+1,j+1); ans(i,j)=sqrt(fx*fx+fy*fy); dir(i,j)=atan(fy/fx); end end figure(3) imshow(ans) for i=2:Isize(1)-1 for j=2:Isize(2)-1 if dir(i,j)>=-pi/8 & dir(i,j)<pi/8</pre> <pre> if ans(i,j)<=ans(i,j-1) | ans(i,j)<=ans(i,j+1) ans(i,j)=0; end end if dir(i,j)>=pi/8 & dir(i,j)<3*pi/8 if ans(i,j)<=ans(i-1,j+1) | ans(i,j)<=ans(i+1,j-1) ans(i,j)=0; end end if dir(i,j)>=3*pi/8 | dir(i,j)<-3*pi/8 if ans(i,j)<=ans(i-1,j) | ans(i,j)<=ans(i+1,j) ans(i,j)=0; end end if dir(i,j)<-pi/8 & dir(i,j)>=3*pi/8 if ans(i,j)<=ans(i-1,j-1) | ans(i,j)<=ans(i+1,j+1) ans(i,j)=0; end end if ans(i,j)<40 ans(i,j)=0; else ans(i,j)=255; end end end figure(4) imshow(ans)
دانلود کد فوق از طریق لینک زیر:
رمز فایل : behsanandish.com
3- الگوریتم Roberts
این الگوریتم به نویز حساسیت زیادی دارد وپیکسل های کمتری را برای تقریب گرادیان بکار می برد،درضمن نسبت به الگوریتم canny هم قدرت کمتری دارد.
clc; clear; close all; warning off; I=imread('siahosefid.bmp'); I=imnoise(I, 'gaussian', 0, 0.001); I=im2double(I); figure(1); imshow(I); [height width R]=size(I); for i=2:height-1 for j=2:width-1 R(i,j)=abs(I(i+1,j+1)-I(i,j))+abs(I(i+1,j)-I(i,j+1)); Z(i,j)=abs(I(i+1,j+1)-I(i,j)); X(i,j)=abs(I(i+1,j)-I(i,j+1)); end end for i=1:height-1 for j=1:width-1 if (R(i,j)<0.25) R(i,j)=0; else R(i,j)=1; end if (Z(i,j)<0.25) Z(i,j)=0; else Z(i,j)=1; end if (X(i,j)<0.25) X(i,j)=0; else X(i,j)=1; end end end figure(2); imshow(Z,[]); figure(3); imshow(X,[]); figure(4); imshow(R,[]);
دانلود کد فوق از طریق لینک زیر:
Robert in Matlab
رمز فایل : behsanandish.com
4- الگوریتم Prewitt
این الگوریتم شباهت زیادی با الگوریتم sobel دارد با این تفاوت که ضرایب ماسک آنها با هم فرق می کند.
I=imread('siahosefid.bmp'); I=im2double(I); I=imnoise(I, 'gaussian', 0, 0.001); figure(1); imshow(I,[]); [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)]+[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)]+[I(i,j+1)-I(i,j-1)]+[I(i+1,j+1)-I(i+1,j-1)]; P(i,j)=sqrt(Dx(i,j)^2+Dy(i,j)^2); if Dx(i,j)<0.5 Dx(i,j)=0; else Dx(i,j)=1; end if Dy(i,j)<0.5 Dy(i,j)=0; else Dy(i,j)=1; end end end figure(2); imshow(Dx,[]); figure(3); imshow(Dy,[]); for i=1:height-1 for j=1:width-1 if (P(i,j)<0.5) P(i,j)=0; else P(i,j)=1; end end end figure(4); imshow(P,[]);
دانلود کد فوق از طریق لینک زیر:
Prewitt In Matlab
رمز فایل : behsanandish.com
5- الگوریتم Zerocross
این الگوریتم قسمت هایی از لاپلاس یک تصویر را جستجو می کند که مقدار لاپلاس از صفر می گذرد. به عبارت دیگر نقاطی که لاپلاس علامت را تغییر می دهد.
[BW,threshOut] =edge(graypic,'zerocross') [BW,threshOut] = edge(graypic,'zerocross',sensitive,filter name);
دانلود کد فوق از طریق لینک زیر:
Zerocross In Matlab
رمز فایل : behsanandish.com
6- الگوریتم LOG)Laplacian of gaussian)
لاپلاس یک اندازه گیری ایزوتروپیک دوبعدی از مشتق فضایی مرتبه دوم از یک تصویر است. لاپلاس یک تصویر، مناطق تغییرات شدت سریع را نشان می دهد و بنابراین اغلب برای تشخیص لبه استفاده می شود.
clc; clear; close all; warning off; f=imread('siahosefid.bmp'); %f=imnoise(f, 'gaussian', 0, 0.001); k=double(f); figure(1) imshow(f) [m,n]=size(f); k=[zeros(m,1) k zeros(m,1)]; k=[zeros(1,n+2);k;zeros(1,n+2)]; T=30; for i=2:m+1 for j=2:n+1 g(i,j)=k(i-1,j)+k(i+1,j)+k(i,j-1)+k(i,j+1)-4*k(i,j); end end for i=2:m+1 for j=2:n+1 if g(i,j)<T g(i,j)=0; else g(i,j)=1; end end end figure(2) imshow(g)
دانلود کد فوق از طریق لینک زیر:
LOG In Matlab
رمز فایل : behsanandish.com
الگوریتم sobel
کد الگوریتم سوبل – متد سوبل لبه ها را با استفاده از تخمین زدن مشتق پیدا می کند، که لبه ها را در آن نقاطی بر می گرداند که گرادیان تصویر I ، max است. پیشنهاد می کنیم جهت آشنایی با الگوریتم های لبه یابی، مطلب «الگوریتم های لبه یابی و انواع آن» را مشاهده نمایید. در فیلتر سوبل دو ماسک به صورت زیر وجود دارد:
ماسک سوبل افقی بیشتر لبه هاي افقی را مشخص میکند و ماسک سوبل عمودي،لبه هاي عمودي را مشخص میکند.
براي مشخص شدن کلیه لبه ها:
اگر Gx و 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)&lt;1 Dx(i,j)=0; else Dx(i,j)=1; end if Dy(i,j)&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)&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 -&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 -&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 &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 &lt; height - filterOffset; OffsetY++) { for (int OffsetX = filterOffset; OffsetX &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 &lt;= filterOffset; filterY++) { for (int filterX = -filterOffset; filterX &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 &gt; 255) bt = 255; else if (bt &lt; 0) bt = 0; if (gt &gt; 255) gt = 255; else if (gt &lt; 0) gt = 0; if (rt &gt; 255) rt = 255; else if (rt &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 ایجاد شد):
رمز فایل : behsanandish.com
کد الگوریتم سوبل( Sobel ) در ++C:
در ادامه دو کد برای الگوریتم Sobel در ++C آماده کردیم:
1.
#include<iostream> #include<cmath> #include<opencv2/imgproc/imgproc.hpp> #include<opencv2/highgui/highgui.hpp> 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<uchar>(y-1, x-1) + 2*image.at<uchar>(y, x-1) + image.at<uchar>(y+1, x-1) - image.at<uchar>(y-1, x+1) - 2*image.at<uchar>(y, x+1) - image.at<uchar>(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<uchar>(y-1, x-1) + 2*image.at<uchar>(y-1, x) + image.at<uchar>(y-1, x+1) - image.at<uchar>(y+1, x-1) - 2*image.at<uchar>(y+1, x) - image.at<uchar>(y+1, x+1); } int main() { Mat src, dst; int gx, gy, sum; // Load an image src = imread("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE); dst = src.clone(); if( !src.data ) { return -1; } for(int y = 0; y < src.rows; y++) for(int x = 0; x < src.cols; x++) dst.at<uchar>(y,x) = 0.0; for(int y = 1; y < src.rows - 1; y++){ for(int x = 1; x < src.cols - 1; x++){ gx = xGradient(src, x, y); gy = yGradient(src, x, y); sum = abs(gx) + abs(gy); sum = sum > 255 ? 255:sum; sum = sum < 0 ? 0 : sum; dst.at<uchar>(y,x) = sum; } } namedWindow("final"); imshow("final", dst); namedWindow("initial"); imshow("initial", src); waitKey(); return 0; }
Sobel in C++-Code1
رمز فایل : behsanandish.com
2.
#include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkSobelEdgeDetectionImageFilter.h" int main( int argc, char* argv[] ) { if( argc != 3 ) { std::cerr << "Usage: "<< std::endl; std::cerr << argv[0]; std::cerr << "<InputFileName> <OutputFileName>"; std::cerr << std::endl; return EXIT_FAILURE; } constexpr unsigned int Dimension = 2; using InputPixelType = unsigned char; using InputImageType = itk::Image< InputPixelType, Dimension >; using ReaderType = itk::ImageFileReader< InputImageType >; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName( argv[1] ); using OutputPixelType = float; using OutputImageType = itk::Image< OutputPixelType, Dimension >; using FilterType = itk::SobelEdgeDetectionImageFilter< InputImageType, OutputImageType >; FilterType::Pointer filter = FilterType::New(); filter->SetInput( reader->GetOutput() ); using WriterType = itk::ImageFileWriter< OutputImageType >; WriterType::Pointer writer = WriterType::New(); writer->SetFileName( argv[2] ); writer->SetInput( filter->GetOutput() ); try { writer->Update(); } catch( itk::ExceptionObject & error ) { std::cerr << "Error: " << error << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }
Sobel in C++-Code2
رمز فایل : behsanandish.com
کد الگوریتم سوبل( Sobel ) در C:
/* sobel.c */ #include <stdio.h> #include <stdlib.h> #include <float.h> #include "mypgm.h" 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("Now, filtering of input image is performed\n\n"); min = DBL_MAX; max = -DBL_MAX; for (y = 1; y < y_size1 - 1; y++) { for (x = 1; x < x_size1 - 1; x++) { pixel_value = 0.0; for (j = -1; j <= 1; j++) { for (i = -1; i <= 1; i++) { pixel_value += weight[j + 1][i + 1] * image1[y + j][x + i]; } } if (pixel_value < min) min = pixel_value; if (pixel_value > max) max = pixel_value; } } if ((int)(max - min) == 0) { printf("Nothing exists!!!\n\n"); exit(1); } /* Initialization of image2[y][x] */ x_size2 = x_size1; y_size2 = y_size1; for (y = 0; y < y_size2; y++) { for (x = 0; x < x_size2; x++) { image2[y][x] = 0; } } /* Generation of image2 after linear transformtion */ for (y = 1; y < y_size1 - 1; y++) { for (x = 1; x < x_size1 - 1; x++) { pixel_value = 0.0; for (j = -1; j <= 1; j++) { for (i = -1; i <= 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 ) در 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 > intMax OrElse intGX * intGX + intGY * intGY > intMax OrElse intBX * intBX + intBY * intBY > intMax Then bmpImage.SetPixel(i, j, Color.Black) Else bmpImage.SetPixel(i, j, Color.Transparent) End If Next Next picModified.Image = bmpImage End Sub
پیشنهاد می کنیم جهت آشنایی با الگوریتم های لبه یابی، مطلب «الگوریتم های لبه یابی و انواع آن» را مشاهده نمایید.
Interpolation يا درون یابی
Interpolation يا درون یابی (كه گاهي resampling نيز ناميده ميشود) يك روش گرافيكي براي افزايش يا كاهش تعداد پيكسلهاي يك تصوير ديجيتالي است. دوربينهاي ديجيتالي از اين روش براي زوم ديجيتال و يا افزايش مصنوعي ابعاد تصوير، نسبت به تصوير اصلي ثبت شده توسط حسگر خود استفاده ميكنند. كيفيت تصوير نهايي حاصل از درونيابي به پيچيدگي الگوريتم ساخت تصوير بستگي دارد. حالتهاي متفاوت درونيابي عبارتند است از:
Nearest Neighbor Interpolation
اين روش سادهترين عمليات درونيابي محسوب ميشود كه اساساً پيكسلهاي بزرگتري را ايجاد ميكند و رنگ هر پيكسل در تصوير جديد، با رنگ نزديكترين پيكسل در تصوير اصلي مطابقت دارد. به عنوان مثال اگر شما يك تصوير را 200 درصد بزرگ كنيد، يك پيكسل تصوير به يك فضاي چهار پيكسلي (دو پيكسل در دو پيكسل) با رنگ پيكسل اوليه تبديل ميشود. بسياري از دوربينهاي ديجيتالي براي زومكردن روي يك سوژه از اين روش استفاده ميكنند. زيرا اين روش هيچ تأثيري بر اطلاعات رنگي تصوير نميگذارد. اصولاً بهتر است از اين روش براي افزايش ابعاد تصوير استفاده نشود. چرا كه موجب ايجاد حالت شطرنجي در تصوير ميگردد.
Bilinear Interpolation
اين روش ارزش يك پيكسل رنگي را براساس چهار پيكسل در جهتهاي عمودي و افقي پيكسل در تصوير اصلي معينميكند. تصوير جديد داراي خاصيت Anti-aliasing است و تقريباً هيچ اثري از پيكسلهاي شطرنجي در آن ديده نميشود.
Bicubic Interpolation
اين روش داراي پيچيدهترين الگوريتم درونيابي است و تصويري كه با اين روش به دست ميآيد، لبههاي بسيارنرمتري پيدا ميكند. در اين حالت پيكسل جديد براساس ارزش تخميني 16 پيكسل (چهار پيكسل در چهار پيكسل) برآوردميشود.
شايان ذكر است كه اغلب دوربينها، چاپگرها و نرمافزارهاي گرافيكي براي تغيير تعداد پيكسلهاي يك تصوير از اين روش استفاده ميكنند.
نرمافزار Photoshop CS دو نوع Sharper و Smoother اين درونيابي را نيز ارائه ميدهد.
Fractal Interpolation
اين روش براي بزرگ كردن تصوير در ابعاد خيلي بزرگ (بهعنوان مثال چاپ روي بدنه يك اتوبوس) روش بسيار مناسبي بهشمار ميرود. زيرا با دقت خوبي ميتواند شكل اجزاي تصوير را حفظ كند. لبههاي بسيار تميزتر و صافتري را نيز برجا ميگذارد. در اين حالت مناطق محوي كه در لبههاي تصوير در روشهاي قبل وجود داشتند، به ندرت ديده ميشوند. البته روشهاي ديگري هم وجود دارند كه جز در برنامههاي گرافيكي پيشرفته، بهندرت از آنها استفاده ميشود.
اشکالات
پلتفرم
منبع چارچوب داتنت مایکروسافت برای اجرا فقط ویندوز است. پیادهسازیهای دیگری برای اجرای برنامههای #C در ویندوز، لینوکس،BSD یا Mac OS X وجود دارند اما هنوز کامل نیستند: Mono و DotGNU در نوامبر سال ۲۰۰۲ توسط مایکروسافت (نسخه ۱٫۰) برای پیادهسازی CLI برای کار در Free BSD و Mac OS X ۱۰٫۲ ارائه شد، اما نسخههای بعدی آنها فقط قابل اجرا بر رویویندوز بود.
پیشرفت در آینده
نسخه بعدی این زبان، سی شارپ ۴ است که از اکتبر سال ۲۰۰۸ در حال ساخته شدن است. مایکروسافت لیستی از ویژگیهای جدید سی شارپ ۴ را در کنفرانس توسعه دهندگان حرفهای اعلام کردهاست. تمرکز اصلی در ورژن بعدی روی قابلیت هماهنگی فریم ورکها و نوع زبانهایی است که کامال پویا یا قیمتی پویا هستند، مانند dynamic language runtime و COM. ویژگیهای زیر تاکنون اعلام شدهاند:
پارامترهای نوع generic از نوع Covariant و contravariant
پارامترهای واسطهای generic و deletageها میتوانند با استفاده از کلمات out و in از دو نوع Covariant و contravariant باشند. این تعیین نوعها بعداً برای تبدیل انواع به یکدیگر، چه از نوع صریح یا مجازی و چه از نوع compile-time یا run-time به کار میرود. به عنوان مثال، واسط IEnumerable<T> در زیر دوباره تعریف شدهاست:
interface IEnumerable < out T > { IEnumerator < T > GetEnumerator(); }
بنابراین، هر کلاس مشتق شدهای که از IEnumerable<Derived> استفاه کرده باشد، با تمام کلاسهای پایه که IEnumerable<Base> را دارند سازگار است. به عنوان تمرین، کد زیر نوشته شدهاست:
void PrintAll(IEnumerable < object > objects) { foreach (object o in objects) { Console.WriteLine(o); } } IEnumerable < string > strings = new List < string > (); PrintAll(strings);// IEnumerable<string> is implicitly converted to IEnumerable < object >
برای contravariance، رابط IComparer < T > به صورت زیر دوباره تعریف شدهاست:
public interface IComparer < in T > { int Compare(T x, T y); }
بنابراین، هر کلاسی که IComparer < Base > را برای یک کلاس پایه بیان میکند، با IComparer < Derived > در تمام واسطها و کلاسهایی که از آن کلاس پایه مشتق شدهاند، سازگار است. این امر نوشتن کد زیر را میسر میسازد:
IComparer < object > objectComparer = GetComparer(); IComparer < string > stringComparer = objectComparer;IComparer < object > objectComparer = GetComparer(); IComparer < string > stringComparer = objectComparer;
جستجوی عضو پویا
در سامانه انواع دادههای #C یک نوع جدید با نام شبه-نوع معرفی شدهاست که مانند System.Object رفتار میکند، ولی در ادامه، هر دسترسی به اعضا یا برنامههایی که از این نوع استفاده میکنند، بدون چک شدن نوع دادههایشان اجازه کار دارند و تجزیه آنها تا زمان اجرا به تعویق میافتد. به عنوان مثال:
// Returns the value of Length property or field of any object int GetLength(dynamic obj) { return obj.Length; } GetLength("Hello, world");// a string has a Length property, GetLength(new int[] { 1, 2, 3 });// and so does an array, GetLength(42);// but not an integer - an exception will be thrown here at run-time
صدا زده شدنهای متد پویا، مانند پارامترهای صریح یا مجازی با مقدار نوع dynamic راهاندازی میشوند. به عنوان مثال:
void Print(dynamic obj) { Console.WriteLine(obj);// which overload of WriteLine() to call is decided at run-time } Print(123);// ends up calling WriteLine(int) Print("abc");// ends up calling WriteLine(string)
جستجوی پویا تحت سه مکانیزم مشخص اجرا میشود: COM IDispatch برای اشیاء COM، رابط IDynamicObject DLR برای اشیاء دارای این واسط و Reflection برای بقیه اشیا؛ بنابراین هر کلاس #C میتواند صدا زده شدنهای پویای خود را با اجرای IDynamicObject در نمونههای خود جدا کند. در مورد متدهای پویا و مشخصکننده صدا زدنها، تجزیه و تحلیل اضافه بار مطابق انواع اصلی که به عنوان آرگومانها هستند، در زمان اجرا اتفاق میافتد، در غیر این صورت بر اساس قوانین تجزیه و تحلیل اضافه بار #C عمل خواهد شد. به علاوه، در مواردی که در صدا زدن پویا، گیرنده خودش پویا نیست، تجزیه و اضافه بار زمان اجرا تنها به متدهایی که در زمان کامپایل به صورت گیرنده ظاهر شدهاند، رسیدگی میکند. به عنوان مثال:
class Base { void Foo(double x); } class Derived: Base { void Foo(int x); } dynamic x = 123; Base b = new Derived(); b.Foo(x);// picks Base.Foo(double) because b is of type Base, and Derived.Foo(int) is not exposed dynamic b1 = b; b1.Foo(x);// picks Derived.Foo(int)
هر مقداری که توسط دستیابی به عضو پویا برگردانده شده باشد، خودش از نوع پویا است. مقادیر نوع پویا به سایر نوعها و از سایر نوع عا قابل تبدیل هستند. در نمونه کد بالا، این امر به تابع GetLength اجازه با مقدار بازگردانده شده از Length بدون هیچ صریحی به عنوان integer استفاده کند. در زمان اجرا، مقدار واقعی به نوع خواسته شده تبدیل میشود.
کلمه کلیدی اختیاری ref
در حال حاضر کلمه کلیدی ref برای متدهای صدا زننده اختیاری است. کد زیر را در نظر بگیرید:
void Increment(ref int x) { ++x; } int x = 0; Increment(ref x);
به صورت زیر هم میتواند نوشته شود:
void Increment(ref int x) { ++x; } int x = 0; Increment(x);
آرگومانهای نامگذاری شده و پارامترهای اختیاری
در سی شارپ ۴ پارامترهای اختیاری ای با مقادیر پیشفرض موجود در ++C معرفی میشوند. به عنوان مثال:
void Increment(ref int x, int dx = 1) { x += dx; } int x = 0; Increment(ref x);// dx takes the default value of 1 Increment(x, 2);// dx takes the value 2
به علاوه، برای کامل کردن پارامترهای اختیاری، میتوانید صریحاً نام پارامترها را در صدازدنهای متدها تعیین کنید. این کار به شما اجازه تصویب کردن انتخابی برای هر زیر مجموعه اختیاری از پارامترهای متد را میدهد. تنها محدودیت موجود این است که پارامترهای نام دار باید بعد از پارامترهای بدون نام بیایند. نام پارامترها میتوانند برای هر دو نوع پارامترهای اختیاری و ضروری تعیین شوند و میتوانند برای بهبود خوانایی و فراخوانی دوباره آرگومانها مفید باشند. به عنوان مثال:
Stream OpenFile(string name, FileMode mode = FileMode.Open, FileAccess access = FileAccess.Read) { ... } OpenFile("file.txt");// use default values for both "mode" and "access" OpenFile("file.txt", mode: FileMode.Create);// use default value for "access" OpenFile("file.txt", access: FileAccess.Read);// use default value for "mode" OpenFile(name: "file.txt", access: FileAccess.Read, mode: FileMode.Create);// name all parameters for extra readability, and use order different from method declaration
پارامترهای اختیاری inter-operating را با COMراحت تر میکنند. در گذشته، #C مجبور بود تمام پارامترهای متد سازنده COM را پشت سر بگذارد، حتی آنهایی را که اختیاری بودند؛ به عنوان مثال:
object fileName = "Test.docx"; object missing = System.Reflection.Missing.Value; doc.SaveAs(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
با پشتیبانی از پارامترهای اختیاری، کد بالا میتواند به صورت زیر خلاصه بشود:
doc.SaveAs("Test.docx");
کتابخانهها
جزئیات مشخصات سی شارپ، حداقل تعداد نوعها و کتابخانههای کلاس است که کامپایلر نیاز به وجود آنها دارد. عملاً، اغلب سی شارپ توسط بیشترین استفاده از CLI را میکند، که استاندارد شده ECMA-۳۳۵ است.
مثال Hello world
در زیر یک مثال ساده از برنامه سی شارپ آمدهاست، نسخهای از مثال کلاسیک Hello World:
class ConsoleApp1 { static void Main() { // a first program in C#.net System.Console.Write("Hello, World!"); } }
نتیجه، چاپ شدن متن زیر در خروجی است:
Hello, world!
هر خط هدفی دارد:
class ExampleClass
در بالا، تعریف کلاس آمدهاست. هر چیزی که در بین در علامت پرانتز باشد،ExampleClass را توصیف میکند:
static void Main()
این یک تابع عضو کلاس را در زمان شروع اجرای برنامه اعلان میکند. دات نت در زمان اجرا، تابع Main را صدا میزند (نکته: Main ممکن است از هر جای دیگری نیز صدا زده شود، مثلاً توسط تابع ExampleClass و با کد ()Main). کلمه کلیدی static تابع را بدون داشتن نمونهای از ExampleClass قابل دسترس میکند. هر تابع Main در هر کنسولی باید به صورت static تعریف شود. در غیر این صورت برنامه به یک نمونه نیاز خواهد داشت و هر نمونه به یک برنامه نیاز دارد. برای اجتناب از این وابستگی دایرهای تجزیه ناپذیر، کامپایلرهای سی شارپ در صورت Static نبودن تابع Main، یک خطا اعلام میکنند. کلمه کلیدی void نشان دهنده این است که تابع Main هیچ مقداری را برنمیگرداند.
Console.WriteLine("Hello, world!");
خط بالا، خروجی را مینویسد. در فضای اسم System, Console یک کلاس استاتیک است که یک میانجی بین ورودی، خروجی و خطای کنسول میباشد. برنامهای که متدWriteLine را از کنسول صدا میزند، خروجی رشته «Hello, world!» را در خروجی نمایش میدهد.
استانداردسازی
در آگوست سال ۲۰۰۰، شرکت مایکروسافت، و Hewlett-Packard و شرکت اینتل به عنوان پشتیبان مشخصات سی شارپ را مانند CLI به سازمان استانداردسازی ECMA ارائه کردند. در دسامبر سال ۲۰۰۱، این سازمان، ECMA-۳۳۴ را با عنوان مشخصات زبان #C منتشر کرد. سی شارپ در سال ۲۰۰۳ به عنوان یک استاندارد ISO به ثبت رسید(ISO/IEC ۲۳۲۷۰). در سال ۲۰۰۲، ECMA دومین ویرایش از خصوصیات زبان سی شارپ را پذیرفت.
در ژوئن سال ۲۰۰۵، ECMA سومین ویرایش را با اضافه کردن مواردی همچون کلاسهای partial، متدهای ناشناس، انواع nullable و Genericها منتشر کرد. در ژوئیه ۲۰۰۵، ECMA استانداردها و TRها را همراه با پردازش Fast-Track اخیر به ISO/IEC JTC پیشنهاد کرد. این روند معمولاً ۶ تا ۹ ماه زمان میبرد. آخرین ویرایش این زبان در ۱۵ آگوست سال ۲۰۱۲ در قالب Framework ۴٫۵ارائه گردید
کارایی
با توجه به توابع موجود در چارچوب داتنت امکان استفاده از این توابع وجود دارد که میتوان گفت برای هر کاری شرکت مایکروسافت تابعی پیشبینی کرده؛ که این امکان را ایجاد میکند که به فایل اصلی پروژه هیچ فایل کتابخانی را اضافه نکنید (هم به صورت دستی یا خود کامپایلر). این موضوع خود باعث ایجاد فایلهای خروجی با حجم بسیار کم میشود. این موضوع در بسیاری از موارد بسیار اهمیت دارد. برنامههای سی شارپ، همچون تمام برنامههای نوشته شده در چارچوب داتنت و سایر محیطهای ماشینی مجازی مانند جاوا، نیازمند منابع سامانه و حافظه بیشتری نسبت به برنامههای نوشته شده با سایر زبانها مانند سی پلاس پلاس است و هم چنین سرعت کمتری نیز دارد. هر چند تعریف زبان سی شارپ و CLI تحت استانداردهای ISO و ECMA استاندارد شدهاند،CLI تنها قسمتی از Base Class Library (BCL) مایکروسافت میباشد که شامل کلاسهای غیر استاندارد استفاده شده در برنامههای #C نیز میشود. از این گذشته، بعضی از قسمتهای BCL تحت حق امتیاز مایکروسافت هستند که ممکن است پیادهسازی کامل framework را مختل کند، زیرا تنها بخشهای استاندارد دارای حق محافظت RAND در برابر مدعیان را دارند.
پیادهسازیها
متداولترین کامپایلر سی شارپ، Microsoft Visual C# میباشد.
- کامپایلرهای سی شارپ
- پروژه Microsoft Rotor (در حال حاضر به عنوان Shared Source Common Language Infrastructure شناخته میشود) (ثبت شده فقط برای استفاده آموزشی و تحقیقی) یک پیادهسازی منبع اشتراکی از CLR Runtime را فراهم میآورد و یک کامپایلر سی شارپ، و یک زیرمجموعه از کتابخانه]] CLI Framework مورد نیاز.
- پروژه Mono یک اوپن سورس از کامپایلر سی شارپ است، یک پیادهسازی اوپن سورس کامل از CLI شامل کتابخانههای Framework مورد نیاز که در ECMA ظاهر شدهاند، و یک پیادهسازی کامل نزدیک به بقیه کتابخانههای اختصاصی کلاس چارچوب داتنت مایکروسافت.
- پروژه DotGNU نیز یک اوپن سورس از کامپایلر سی شارپ است، که پیادهسازی آن بسیار نزدیک به Common Language Infrastructure میباشد و کتابخانههای framework مورد نیاز موجود در ECMA و زیر مجموعهای از کلاسهای کتابخانهای شخصی مایکروسافت در دات نت و دات نت ۲ را دربردارد.
کاملاً شبیه به پروژه Mono.
نام زبان
اسم سی شارپ از علامت موسیقی شارپ گرفته شدهاست که در موسیقی بیان گر این است که متن نوشته شده باید نیم قدم از خط بالاتر باشد. مطابق با ECMA-۳۳۴، بخش ۶، مخففها و اختصارها، نام زبان به صورت «#C» نوشته میشود(«کلمه لاتین C (U+۰۰۴۳) به همراه علامت عددی #(U+۰۰۲۳)») که به صورت «سی شارپ» تلفظ میشود. علامت «#» نباید با علامت شارپدر موسیقی(♯، U+266F) که در یک صفحه کلید استاندارد وجود ندارد اشتباه گرفته شود. پسوند شارپ، توسط بسیاری دیگر از زبانهای دات نت مانند #J، #A و #F نیز به کار رفتهاست. پیادهسازی اولیه از زبان ایفل تحت دات نت نیز #Eiffel نام داشت که الان زبان ایفل را بهطور کامل پشتیبانی میکند. هم چنین این پسوند بعضی وقتها در کتابخانهها نیز به کار میرود، مانند #Gtk، #Cocoa و#Qt.
کلمات اختصاری به کار رفته در این متن
- PDC: Professional Developers Conference
- IL (MSIL): Microsoft Intermediate Language
- ECMA: European Computer Manufacturers Association
- BCL: Base Class Library
- CLI: Common Language Infrastructure
- CLS: Common Language Specification
- IEC: International Electrotechnical Commission
- ISO: International Organization for Standardization
- SDK: Software Development Kit
- LINQ: Language Integrated Query
منبع
کانال شرکت بهسان اندیش در سایت اشتراک ویدئو آپارات (Aparat)
کانال شرکت بهسان اندیش در سایت آپارات – در دنیای مجازی که شبکه های اجتماعی همچون کشوری مستقل عمل می کنند دسته ای از کاربران متناسب با فعالیت خود نیاز به امکاناتی خاص تر دارند. سازمان های دولتی و خصوصی، برند ها، شخصیت های سیاسی، هنری، فرهنگی و… برای ایجاد ارتباط و پیشبرد فعالیت خود نیاز به اعتماد مخاطب دارند.
در شبکه های اجتماعی ، گاه هویت واقعی یک کاربر مشخص نیست و ممکن است دیگران به اسم سازمان ها و اشخاص صفحاتی را ایجاد کنند و نام آن برند یا شخص را خدشه دار نمایند و با توجه به آنکه ایجاد اعتماد در مخاطب، امری مشکل است ، آپارات با رسمیت بخشیدن به صفحات و تایید آنها این رویکرد را متفاوت کرده است.
شرکت بهسان اندیش به منظور ارائه خدمات و فعالیت های خود در شبکه های اجتماعی اقدام به راه اندازی کانال شرکت بهسان اندیش در سایت آپارات نموده که علاقمندان می توانند از طریق لینک زیر در این سایت ما را دنبال کنید:
ورود به صفحه شخصی شرکت بهسان اندیش در سایت اشتراک ویدئو آپارات
بهینهسازی چیست؟
بهینهسازی یک مسئله ریاضی و کلی است که از قرنها پیش مطرح بوده است و در حال حاضر هم یک مسئله و موضوع در دست بررسی و پژوهش است. هنوز راه حلی کلی برای تمام مسائل بهینهسازی مطرح نشده است. البته در بعضی موارد محدود که در آن تابع هدف کاملا مشخص شده و معین است و مسائلی مانند مشتقپذیری در آن وجود دارد؛ میتوانیم بصورت دقیق آن را حل کنیم. در بعضی از مسائل هم جواب نهایی وجود دارد ولی زمان محاسبه آن بسیار زیاد طول خواهد کشید. با این حال هنوز برای بعضی از مسائل راه حل معقول و مشخصی ابداع نشده است. بر همین اساس، طبقهبندیهای مختلفی برای اینگونه مسائل از لحاظ پیچیدگی و یا پارامترهای دیگر تعیین شده است. بطور مثال: مسائل برنامهریزی خطی (LP)، برنامهریزی غیر خطی (NLP)، مسائل درجه دوم (QP)، مسائل NP,NP-hard و…
مسئله فروشنده دورهگرد (TSP)
یکی از سادهترین و در عین حال، پرکاربردترین و مفیدترین مسائل مطرح شده در حوزه بهینهسازی مسئله فروشنده دورهگرد (Traveling Salesman Problem) است.
در این مسئله فرض شده است که یک فروشنده دورهگرد قصد دارد N شهر را بگردد و برای این موضوع یک سری شرایط مطرح شده است. بطور مثال از یک شهر نباید دوبار عبور کرد و از همه شهرها باید یک بار عبور کند و دوباره به شهر اولیه برگردد. سوالی که اینجا پیش میآید و مورد بررسی قرار میگیرد این است که چگونه این فروشنده در کمترین زمان، این مسافرت را طی می کند و یا اینکه چگونه کمترین مسافت را در این سفر خواهد داشت؟
این مسئله در طبقهبندی مسائل NP-hard قرار میگیرد و روشهای عادی نمی تواند پاسخی برای این مسئله پیدا کند. اما بعضی از الگوریتمهای فراابتکاری و یا تکاملی، میتوانند در این خصوص پاسخ نه کاملا بهینه اما نزدیک به آن را به ما بدهند.
این مسئله و حل آن میتواند در مسائل صنعتی زیادی به ما کمک کند و کاربرد داشته باشد. بطور مثال تعیین مسیر رباتهایی که کار سوراخ کردن فیبرهای مدار چاپی را انجام میدهند. و همچنین مسائل صنعتی دیگری مانند زمانبندی و…
بصورت کلی بیشتر سیستمهای زمانبندی و توزیع میتوانند به نوعی از این مسئله الگوبرداری کنند. هر جا صحبت از ظرفیت است و میخواهیم از کمترین ظرفیت استفاده کنیم مسئله ما جایگشتی است و باید از روش و الگوی مسئله TSP کمک گرفته شود.
برای حل این مسئله باید تمام راه حلهای ممکن و یا حداقل بیشتر آنها بررسی شود تا به جواب و راه حل بهتر دست پیدا کنیم. مشکل ما در این بررسی، فاکتور زمان است. بطور مثال اگر در مسئله فروشنده دوره گرد N شهر داشته باشیم؛ N فاکتوریل هم راه حل خواهیم داشت.
ارتباط بهینهسازی و الگوریتمهای فراابتکاری
بصورت کلی در حل مسائل بهینهسازی، مشکلی که ما با آن روبرو هستیم این است که یک مسئله دارای بینهایت راه حل و پاسخ باشد و ما باید بهترین پاسخ را در بین آنها پیدا کنیم. در واقع عمل جستجو (search) و بهینهسازی (optimization) در این مسائل بکار برده می شوند و از یک نوع معقوله و در راستای هم هستند و الگوریتمهایی در این جا کاربردی تر هستند که یک بخش عمده پاسخها را بررسی کنند و در بین آنها به جواب نهایی برسند.
بهترین و کارآمدترین الگوریتمها باید یک سری ویژگیها را داشته باشند. بطور مثال: قابلیت کشف و جستجوی بالا (exploration) و قابلیت استخراج کردن (exploitation)
الگوریتمهای بهینهسازی کلاسیک، اغلب این قابلیتها را به صورت متعادل ندارند. بطور مثال قابلیت Global search برای استخراج کردن را ندارند. مکانیزم این گونه الگوریتمها Local search است. همچنین الگوریتمهای Random search (جستجوی تصادفی) در این بین هستند که Global search خوبی دارند ولی در نهایت نمی توانند به همگرایی مورد نیاز برسند. در واقع روشی که در بین این الگوریتمها بصورت هوشمندانه عمل کند و در نهایت به همگرایی برسد، همان الگوریتمهای فراابتکاری و تکاملی است.
الگوریتم ژنتیک
یکی از الگوریتمهای تکاملی و فراابتکاری، الگوریتم ژنتیک است که از طبعیت ژنتیکی، وراثت، جهش در کروموزم ها و تئوری انتخاب داروین الگوبرداری کرده است. در این الگوریتم ابتدا یک سری جواب و پاسخ و یا راه حل مطرح میشود و بعد از آن، راه حلها مانند اتفاقی که در زاد و ولد حیوانات میافتد با هم ترکیب میشوند. این موجودات یک سری از ویژگیهای خودشان را برای فرزندانشان به ارث میگذارند. اگر فرزند از هر دو والد خود یعنی پدر و مادر، یک ویژگی خوب را به ارث ببرد، نتیجه و جواب بهتری خواهیم گرفت. این روش و الگوریتم نه به صورت کاملا Random و تصادفی و نه کاملا به صورت حریصانه عمل میکند و در واقع روشی بین این دو است و به همین علت یک روش کارآمد محسوب می شود.
در این روش نمی توان هم به همگرایی بالایی در کمترین زمان رسید و هم تمام مناطق را به صورت کامل جستجو کرد. با افزایش هر کدام از این پارامترها دیگری کاهش پیدا می کند. اما اغلب الگوریتمهای تکاملی، یک توازن نسبی بین این دو را برقرار کردهاند و منشا بیشتر و کارآمدترین آنها طبیعت است.
دیگر الگوریتمهای فراابتکاری
الگوریتمهای دیگری نیز در حوزه بهینهسازی و محاسبات تکاملی مطرح شده اند مانند: الگوریتم مورچگان (ACO)، الگوریتم ازدحام ذرات (PSO)، الگوریتم کلونی زنبور عسل (ABC)، الگوریتم رقابت استعماری (ICA) و …
نقطه مشترک این الگوریتمها، استناد به یک پدیده طبیعی و واقعی است. بطور مثال الگوریتم ازدحام ذرات از کوچ پرندگان و الگوریتم رقابت استعماری از روابط اجتماعی و انسانی الهام گرفته شده است و همین پدیدهها را تبدیل به یک مدل ریاضی و روش حل مسئله بهینهسازی میکنند.
همان طور که قبلا ذکر شد؛ مسئله بهینهسازی با عمل جستجو (search)، رابطه مستقیم دارد و ارتباط این موضوع با الهام گرفتن این الگوریتمها از طبیعت به این صورت است که بطور مثال مورچگان، همیشه به دنبال بهترین منبع غذایی و ذخیره کردن آن هستند. زنبورها به دنبال بهترین گل برای تهیه عسل هستند و بطور کلی طبیعت به دنبال این است که مقاومترین و برترین موجودات را بسازد.
در ارائه این الگوریتمها از یک زمانی به بعد، الگوریتمهای مشابه زیادی معرفی شد و بعضی از آنها گاها بسیار به هم شباهت دارند و تفاوت آنها در بعضی مواقع، در حد اسم آنها است. اما هنوز هم این حوزه مورد مطالعه و رو به رشد است و جای پیشرفت بیشتری هم دارد. بطور مثال بهینهسازی چند هدفه، یکی از شاخههای جذاب بهینهسازی است که می تواند مورد مطالعه بیشتری قرار گیرد.
منابع
بهينهسازی و معرفي روشهای آن قسمت 1
بهينهسازی و معرفي روشهای آن قسمت 2
بهينهسازی و معرفي روشهای آن قسمت 3
تلفن های تماس:
تلفن: ۹۱۰۰۱۸۸۱(۰۳۱)
بازرگانی و فروش:۰۹۱۳۶۵۳۱۸۸۱
پشتیبانی: ۰۹۱۱۷۶۱۰۲۷۵
ساعات کاری
از شنبه تا چهارشنبه : ۰۹:۰۰ تا ۱۷:۰۰
پنچ شنبه ها : از ۰۹:۰۰ تا ۱۳:۳۰