PDA

View Full Version : سوال: تشخیص عکس از پس زمینه سفید (autocrop)



arghavan92
شنبه 25 مرداد 1393, 16:48 عصر
با سلام
برنامه ای که میخوام بتویسم automatic crop هست،فرض کنید چندتا عکس کنار هم اسکن شده اند، برنامه باید این عکس ها رو شناسایی و جدا کنه و ذخیره کنه، برای حذف قسمت های سفید از عکس اسکن شده چه پیشنهادی دارید؟

aminmousavi
دوشنبه 27 مرداد 1393, 03:15 صبح
سلام دوست عزیز . چون اساتید تالار جواب ندادن ، روش پیشنهادی خودم رو میگم که شاید روش های بهتری هم باشه !
بنظر بنده برای پیاده سازی همچین برنامه ای باید یکسری استاندارد هایی برای فایل ورودی در نظر بگیرین ، فرض کنین من در نظر میگریم عکس ها فقط کنار هم باشن زیر هم عکس اسکن نشه :

- اول پیکسل های عکس رو درون یک ماتریس ذخیره کنید
- بعد شروع کنید به پیمایش پیکسل ها به صورت افقی- عمودی (با 2 تا حلقه اولیش افقی باشه داخلی عمودی)
- یک بازه رنگ برای مقدار سفید بودن در نظر بگیرین (چون سفیدی که شما میبینید کد های hex مختلفی دارن ) مثلا اگر رنگ پیکسل ffffff تا eeeeee یعنی تو قسمت سفید تصویر هستین

- اول حلقه دومی ، به محض اینکه بعد از سفید یک پیکسل رنگی دیدید اون رو توی یک آرایه ای از Point ذخیره میکنین و بعد از اینکه اولین پیکسل رنگی توی اون ستون جاری رو ذخیره کردید هر پیکسل رنگی که دیدید رو درون یک متغیر بافر به صورت موقت ذخیره میکنین تا وقتی که پیمایش اون ستون انجام شه ، وقتی پیمایش اون ستون تمام شد (حلقه اولی یک دور زد) متغیر بافر رو ذخیره میکنین توی آرایه (به عنوان آخرین پیکسل رنگی اون ستون) .
- اینکار رو انقدر انجام میدین تا عکس اولی پیمایش بشه ، اگر به یک ستون رسیدید که رنگ نداشت یعنی عکس اول پیمایش اش تموم شده
- حالا با این کار شما توی آرایه مختصات لبه عکستون رو دارید کافیه با یکسری شرط و مقایسه در آرایه مشخص کنید 4 ضلع عکس شما چه x,y دارن ، بعدش میتونین با استفاده از اون 4تا نقطه ، اون عکس رو crop کنین .

- برای بقیه عکس ها هم همین عملیات رو انجام میدین

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

arghavan92
دوشنبه 27 مرداد 1393, 13:58 عصر
ممنون، با فرض شرط ایجاد شده برای فایل ورودی پیشنهادتون خیلی بهم کمک میکنه، ولی اگه عکس ها موقع اسکن مرتب کنار هم قرار نگیرند و کج باشند چی؟!؟ راهی برای پیدا کردن مختصات چهارگوشه عکس هست؟

aminmousavi
دوشنبه 27 مرداد 1393, 15:55 عصر
سلام مجدد ، من با فرض این که عکس ها کج هست اون الگوریتم رو معرفی کردم ، عکس زیر رو در نظر بگیر :

122399
اون لبه (حاشیه) مشکی پیکسل هایی هست که شما در آرایه ذخیره کردید ، پس شما در اصل پیکسل های دور تا دور عکستون رو دارید ، حالا کافیه توی آرایه سرچ کنید مثلا:

- کمترین y و کمترین x میشه گوشه بالا - چپ تصویر
- بشترین y و کمترین x میشه گوشه پایین - چپ تصویر
- کمترین y و بیشترین x میشه گوشه بالا - راست تصویر
- بشترین y و بیشترین x میشه گوشه پایین - راست تصویر

حالا کافیه بزرگترین مستطیل رو با این 4تا نقطه بسازید ، به شکل زیر
122401
درسته اگر عکس کج باشه شما هم کج توی کراپ در نظر میگیرینش ، اما میتونه عملیات شما چند فاز داشته باشه ، فاز اول کراپ ، فاز دوم Rotate .

arghavan92
شنبه 08 شهریور 1393, 13:12 عصر
الان متوجه شدم،ممنون، حالا یه سوال دیگه، برای پیمایش عکس به این طریق عکس هر dpi ای داشته باشه که فرق نمی کنه؟!؟!؟ یعنی پیمایش پیکسل به پیکسل انجام میشه ؟؟!:متفکر::خجالت:

aminmousavi
شنبه 08 شهریور 1393, 13:54 عصر
نه فرقی نمیکنه ، هرچی عکس شما بزرگتر ، پردازش هم سنگین تر و طولانی تر

NASA's Spaceman
شنبه 08 شهریور 1393, 15:59 عصر
میبخشید میشه یکی یه نمونه از این رو بزاره
ممنون میشم
با سپاس Spaceman

aminmousavi
شنبه 08 شهریور 1393, 16:10 عصر
تا چند روز دیگه اگر تونستم حتما میزارم براتون

arghavan92
دوشنبه 10 شهریور 1393, 12:36 عصر
پروژه من باید طوری نوشته بشه که عکس به هرشکلی هرجای تصویر که بود کراپ بشه، یعنی نمی تونم شرط بذارم که کنار هم قرار بگیرند، برای لبه یابی تصویر باید چی کار کنم؟ الگوریتم لبه یابی چیه؟:متفکر:

aminmousavi
دوشنبه 10 شهریور 1393, 16:42 عصر
اگر بخوایم هرجای صفحه بود کراپ بشه ، با الگوریتم قبلی هم میتونین پیاده سازی کنین ، اما شرط هایی باید براش بزارین که پیچیدگی نرم افزارتون رو زیاد میکنه (اگر زیاد تجربه برنامه نویسی هم ندارین کارتون خیلی سخت تر میشه)

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

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

aminmousavi
دوشنبه 10 شهریور 1393, 17:02 عصر
یک الگوریتم دیگر هم که ذهنم رسید . (اگر با هوش مصنوعی آشنایی داشته باشید بهنر درک میکنید) ، میتونین فقط در جاهای سفید حرکت کنین !
اگر بخوام شفاف تر بگم ، فرض کنید یک آدم توی یک پیکسل قرار بدیم ، و بهش بگیم فقط توی جاهای سفید میتونی حرکت کنی ! وقتی شروع میکنه آدمه به حرکت دیگر پا روی پیکسل های رنگی نمی زاره ! فقط از کنارشون رد میشه ، و فقط پا روی تمام پیکسل های سفید میزاره ، برای اینکه لبه رو بدست بیارین کافیه به اون آدمه بگین توی حرکت در پیکسل های سفید هر پیکسل رنگی که دید مختصاتش رو برداره ، اینجوری کل لبه ها رو دارید ! (فکر میکنم روش بهینه تری باشه)

NASA's Spaceman
دوشنبه 10 شهریور 1393, 17:42 عصر
دوست عزیز لطفا یه نمونه بزار
با سپاس Spaceman

arghavan92
سه شنبه 11 شهریور 1393, 11:58 صبح
یک الگوریتم دیگر هم که ذهنم رسید . (اگر با هوش مصنوعی آشنایی داشته باشید بهنر درک میکنید) ، میتونین فقط در جاهای سفید حرکت کنین !
اگر بخوام شفاف تر بگم ، فرض کنید یک آدم توی یک پیکسل قرار بدیم ، و بهش بگیم فقط توی جاهای سفید میتونی حرکت کنی ! وقتی شروع میکنه آدمه به حرکت دیگر پا روی پیکسل های رنگی نمی زاره ! فقط از کنارشون رد میشه ، و فقط پا روی تمام پیکسل های سفید میزاره ، برای اینکه لبه رو بدست بیارین کافیه به اون آدمه بگین توی حرکت در پیکسل های سفید هر پیکسل رنگی که دید مختصاتش رو برداره ، اینجوری کل لبه ها رو دارید ! (فکر میکنم روش بهینه تری باشه)
این روش کلی تره، ولی بعد از ذخیره پیکسل های رنگی چجوری پیکسل های هر عکس رو از بقیه تفکیک کنم؟ آخه ممکنه دو تا عکس خیلی به هم نزدیک باشند و اگه دورشون یه چهارضلعی در نظر بگیریم این چهار ضلعی ها تداخل داشته باشن!

aminmousavi
سه شنبه 11 شهریور 1393, 12:11 عصر
بگیم اصولیتره بهتره .
توی روش قبل شما تقریبا همچین مشکلی هم دارید ، متوجه نمیشید که بلاخره نقاطی که برگردونه نرم افزار برای کدوم عکسه ! باید با یک الگوریتم دیگه نقاط رو از هم تفکیک کنید ، قبول دارم روش قبلی راحت تر هست و شاید حتی سریعتر ! اما شرایط خاص هم داره اگر دقت کرده باشین ، مثلا فرض کنید وسط عکس پیکسل رنگی باشه که قبلش پیکسل سفیده ! اون الگوریتم اون رو به عنوان لبه در نظر میگیره ، بعدا شما باید بعد بدست آوردن لبه ها مقداری فیلتر انجام بدید تا لبه های واقعی هر عکس رو پیدا کنید .
روش دوم اما چون از روی عکس ها اصلا حرکت نمیکنه ، این مشکل براش پیش نمیاد .
در خصوص نزدیک بودن هم اگر حتی یک پیکسل بینشون فاصله باشه ، مشکلی پیش نمیاد ، اما اگر تصاویر و شکلاتون تداخل داشته باشن که خوب مشخصه به خوبی عمل نمیکنه !

elec60
سه شنبه 11 شهریور 1393, 12:49 عصر
براي لبه يابي از الگوريتم Canny و يا Sobel استفاده كنين

aminmousavi
چهارشنبه 12 شهریور 1393, 17:19 عصر
یک الگوریتم دیگر هم که ذهنم رسید . (اگر با هوش مصنوعی آشنایی داشته باشید بهنر درک میکنید) ، میتونین فقط در جاهای سفید حرکت کنین !
اگر بخوام شفاف تر بگم ، فرض کنید یک آدم توی یک پیکسل قرار بدیم ، و بهش بگیم فقط توی جاهای سفید میتونی حرکت کنی ! وقتی شروع میکنه آدمه به حرکت دیگر پا روی پیکسل های رنگی نمی زاره ! فقط از کنارشون رد میشه ، و فقط پا روی تمام پیکسل های سفید میزاره ، برای اینکه لبه رو بدست بیارین کافیه به اون آدمه بگین توی حرکت در پیکسل های سفید هر پیکسل رنگی که دید مختصاتش رو برداره ، اینجوری کل لبه ها رو دارید ! (فکر میکنم روش بهینه تری باشه)


دوستان یک نمونه با روشی که گفته بودم براتون نوشتم ، میتونین از لینک زیر دانلود کنین :
http://www.greendeveloper.ir/DownloadView/21/12/%D8%A8%D8%B1%DB%8C%D8%AF%D9%86-%D8%AA%D8%B5%D9%88%DB%8C%D8%B1-%D8%A8%D9%87-%D8%B5%D9%88%D8%B1%D8%AA-%D8%A7%D8%AA%D9%88%D9%85%D8%A7%D8%AA%DB%8C%DA%A9

اگر سوالی داشتید ، در خدمتم
موفق باشید

NASA's Spaceman
چهارشنبه 12 شهریور 1393, 19:27 عصر
ممنون دوست عزیز
حالا اگه بخوایم اون عکس های جدا شده رو transparent کنیم باید چیکار کنیم؟
با سپاس Spaceman

aminmousavi
چهارشنبه 12 شهریور 1393, 20:40 عصر
اگر تکه کد رو بخونین ، مانند همان پیمایشی هست که در متد SearchingNode انجام میشه کافیه فقط اون قسمتی که توی if سفید میره (قسمت else) اونجا ست پیکسل رو با ترنسپرنت انجام بدین

arghavan92
دوشنبه 24 شهریور 1393, 13:34 عصر
با سلام
میشه در مورد قسمت searching node بیشتر توضیح بدین
(if (pixcels[3, point.X, point.Y] != 69 یعنی چی؟
NodeFringe و NodeLedge دقیقا چی رو نگه می دارن؟

aminmousavi
دوشنبه 24 شهریور 1393, 18:51 عصر
سلام دوست عزیز .
توی متد Searching Node میایم کل پیکسل هایی که مجاورت دارن با پیکسل های سفید بیرونی رو استخراج میکنیم ، همانطور که توی پست 11 عرض کردم ، از یک نقطه سفید (0،0) شروع به حرکت میکنیم و فقط باید درون پیکسل های سفید حرکت کنیم هرگاه به پیکسل رنگی برسیم اون رو ذخیره میکنیم . (درون NodeLedge ذخیره میشن ، به این نکته توجه کنین که نقطه هایی که درون NodeLedge ذخیره میشن ، لبه های تمامی تصاویر هست که بعدا با متد FindBitmap تصاویر رو جدا میکنیم)

در خصوص NodeFringe به طور خلاصه بخوام بگم پیکسل های کاندید ما هستن نقاطی که درون اون ذخیره میشن (اگر مایلید اطلاعت بیشتری کسب کنید میتونین مبحث های مسیریابی DFS یا BFS که جزو ساده ترین اگوریتم های مسیریابی هوش مصنوعی هستن رو مطالعه کنید)

فرض کنین شما درون پیکسل 0,0 قرار داشته باشین (همانطور که توی متد ClearSetting این اتفاق میوفته) ، شما توی پیکسل 0,0 هستین و میخواین کل پیکسل های سفید رو پیمایش کنید (فقط سفید ها رو) ، در هر پیکسلی که قرار داشته باشین شما 4 تا انتخاب برای حرکت دارین : بالا برین ، پایین برین ، راست برین و چپ برین . پس این چهار پیکسل میشن پیکسل های کاندید شما (X-1 , X+1, Y-1 , Y-2) . اما توی این حالت یک مشکلی پیش میاد که شما همیشه دور خودتون میچرخین ! چون فرض کنین از پیکسل 0,0 میرین به 0,1 و چون پیکسل 0,0 (Y-1) جزو کاندید های شما برای حرکت کردن هست شما بعدا دوباره میرین توی پیکسل 0,0 و همیشه در حال حرکت هستین و برنامه هیچوقت تموم نمیشه !
پس باید برای حلش باید جاهایی که میریم رو یادمون باشه پس هر پیکسلی که پیمایش میکنیم مقدارش رو برابر با 69 قرار میدیم که جای تکراری نریم !

در خصوص NodeFringe هم اگر دقت کرده باشین شرط داره که پیکسل قبلا پیمایش نشده باشه (برابر با 69 نباشه) ، بعدش رنگ پیکسل رو بررسی میکنیم که رنگی هست یا نه ، اگر رنگی باشه به عنوان لبه ذخیره میشه در غیر اینصورت پس پیکسل جاری سفید هست و 4تا کاندید رو درون فرینج ذخیره میکنیم ، زمانی پیمایش تمام میشه که فرینج خالی بشه ، یعنی ما در عکس با پیکسل های عکس کاری نداریم ، با نقطه های درون فرینج کار داریم برای پیمایش ! اول 0,0 درونش هست و بعد نقاط همسایه 0,0 درون فرینج قرار میگرن و 0,0 از فرینج پاک میشه (چون پردازش شده) و بعدش نقطه بعدی درون فرینج بررسی میشه و نقطه های کاندیدش درون فرینج (اگر دارای شرط ها باشن) ذخیره میشن و همینطور ادامه پیدا میکنه که فرینج خالی بشه .

raha kh
دوشنبه 24 شهریور 1393, 20:47 عصر
با سلام
ببخشید ی سوالی داشتم.::متفکر:
میشه بگید این 4 تا کلاسی که به نام های CropPattern,Draw,hex,Render نوشتین مربوط به چی میشه دقیقا؟؟؟
میشه راجبشون بیشتر توضیح بدین؟؟ :خجالت:
خیلی ممنون

aminmousavi
دوشنبه 24 شهریور 1393, 21:51 عصر
سلام دوست عزیز .
CropPattern : در این پروژه استفاده ای ازش نمیشه و اشتباها Import کردم در پروژه
Hex : برای تبدیل های هگزادسیمال است (تبدیل عدد هگز به عدد ده دهی یا همان اعداد مورد استفاده روزانه ، و تبدیل نوع Color به هگز) که توی این پروژه از متد اول برای مقایسه رنگ استفاده شده .
Draw : برای رسم اشکال بر روی Bitmap ازش استفاده میشه ، مثل Line,Rectange,... که توی این پروژه برای نمایش لبه های عکس از این کلاس استفاده شده
Render : برای بدست آوردن پیکسل های تصویر ازش استفاده میشه

raha kh
سه شنبه 25 شهریور 1393, 11:39 صبح
با سلام مجدد
میشه راجب checking color بیشتر توضیح بدین؟؟
[( Color clr = Color.FromArgb(pixcels[0, _x, _y], pixcels[1, _x, _y], pixcels[2, _x, _y

ارگومان اول از ارایه پیکسل معرف چیه؟در متد searching node هم عدد 3 رو گذاشته بودین.چرا؟؟

aminmousavi
سه شنبه 25 شهریور 1393, 11:47 صبح
متد Checking Color بررسی میکنه که آیا پیکسل رنگی هست یا نه .
در خصوص آرایه هم برای RGB هست .
رنگ قرمز در خانه _x,_y : pixcels[0, _x, _y]
رنگ سبز در خانه _x,_y : pixcels[1, _x, _y]
رنگ آبی در خانه _x,_y : pixcels[2, _x, _y]

در خصوص pixcels[3, point.X, point.Y] != 69 در پست20 جوابش رو دادم ، مطالعه کنید

arghavan92
پنج شنبه 27 شهریور 1393, 12:50 عصر
سلام مجدد
من میخوام برای برنامه یه progress bar بذارم(برای دکمه شروع عملیات)، برای این کار توی این قسمت از timer1_Tick :
( if (status==StatusProgress.Render && chkPointer.Checked
یکی یکی به مقدار progress bar اضافه میکنم و توی
(if (status==StatusProgress.Finish
مقدارش رو 100 میکنم، interval رو هم 100 گذاشتم، ولی progressbar متناسب با برنامه پر نمیشه( که یه چیز بدیهیه!)
میشه یه راه حل پیشنهاد بدین؟!

aminmousavi
پنج شنبه 27 شهریور 1393, 14:19 عصر
سلام .
برنامه از دو عملیات اصلی تشکیل شده همانطور که میدونید ، یکی پیمایش تصویر و دومی پیدا کردن تصاویر از لبه های بدست آمده.
برای ProgressBar گذاشتن توی عملیات اول به مشکل میخورین ! چون به طور کل معلوم نیست چه پیکسل هایی قرار هست پیمایش بشه ، خود برنامه هم نیمدونه تعداد پیمایش و مقایسه در هر عکس متفاوت هست . به این دلیل که هیچوقت پاتون رو روی پیکسل های رنگی نمیزارین ! پس اصلا نمیتونیم بفهیم چند تا پیکسل کنار هم قرار داشتن که بخوایم براش ProgressBar بزاریم . تنها کاری که میشه کرد یک ProgressBar گذاشتن برای پیکسل هایی که پیمایش میشه که دقیق نیست اما بهتر از هیچی هست ، برای اینکار شروع برنامه Progressbar اولی max برابر با کل پیکسل های تصویر میشه و هر بار که While متد SearchingNode اجرا میشه به مقدار Progressbar اضافه میشه و وقتی از حلقه خارج شد مقدار ProgreessBar رو برابر با Max میکنین .
اما برای عملیات دوم کارتون سادست چون تعداد لبه های رو میدونیم . پس مقدار max پروگرس بار رو برابر با تعداد NodeLedge قرار میدیم (در متد FindBitmap) و در حلقه while اولی

while (NodeLedge.Count > 0)

کافیه مقدار فعلی Progressbar رو با مقداره تفاضل max پروگرس بار با تعداد فعلی که در NodeLedge هست قرار بدین