PDA

View Full Version : خواندن رنگ پیکسلها از یک PictureBox



(سیدشریفی)
پنج شنبه 06 مرداد 1384, 09:11 صبح
با سلام خدمت دوستان گرامی
من با vb6 کار میکنم و برنامه ای نوشته ام که لازم است در قسمتی از این برنامه رنگهای پیکسل مشخصی را از یک pictureBox بدست آورم و موقعی که میخواهم این کار را برای کل پیکسلهای یک جعبه تصویر انجام دهم سرعت کار خیلی پائین میباشد .
حال از شما خواهش میکنم در صورت امکان یک دی ال ال در ++c برای این کار بنویسید تا سرعت برنامه من از این طریق زیاد شود .
چگونگی کار این دی ال ال بدین طریق میباشد که در vb6 یک PictureBox برای آرگومان آن ارسال میکنیم و برای ما مختصات و رنگ تک تک پیکسلهای جعبه تصویر را معین میکند .

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

:)

(سیدشریفی)
یک شنبه 09 مرداد 1384, 09:28 صبح
کسی نیست کمک کنه ؟

(سیدشریفی)
یک شنبه 16 مرداد 1384, 08:46 صبح
فکر نمیکنم سوالی که من پرسیده ام زیاد سخت باشد .
در VB که این کار براحتی صورت میگیرد حتما در ++c نیز این کار راحت میباشد .
نمیدانم دلیل پاسخ ندادن دوستان به سوال من چیست .
بهرحال مطمئنم دلیل آن بلد نبودن آن نیست .
دوستان اگر سوال من واضح نیست بگویید تا بیشتر توضیح بدهم .

ghafoori
پنج شنبه 20 مرداد 1384, 23:21 عصر
در سی ++ 6 باید یک متغیر از نوع dc تعریف کنید و با استفاده از تابع getpixelان رنگ پیکسل را بدست اورد
مثلا کد زیر فورم یک dc ایجاد میکند و رنگ پیکسل را در متغیری از نوع colorrefمی ریزد
cclientdc dc(this
colerref color
color=dc.getpixel(intx,inty
درسی ++ دات نت باید تابع api را تعریف کنید که من به اینکار وارد نیستم
برای اطلاع بیشتر به کتابهای سی++ جعفر نژاد قمی انتشارات علوم رایانه و یا اموزش سی++دات نت انتشارات نشر علوم مراجعه کنید
اگر از دات نت استفاده می کنید پی شنهاد می کنم از vb.netاستفاده کنید بسیار راحتر است می توانید از کد زیر استفاده کنید
declare function getpixel Lib "gdi32" (ByVal hdc As Intptr, ByVal X As Integer, ByVal Y As Integer) As Integer
public function getpix(baval pic as picturebox)as color
dim a as intptr
dim color as color
a=pic.creategraphics.gethdc
color=color.fromargb(getpixel(a,100,100))
return color
end function

تابع زیر رنگ پیکسل 100 100 را بر میگرداند شما میتوانید این تابع را بصورت dllدر اورید و در سی++دات نت استفاده کنید

(سیدشریفی)
یک شنبه 23 مرداد 1384, 08:09 صبح
جناب ghafoori
از جوابی که دادید خیلی ممنون
اگر به سوال من دقت کنید نوشته ام با VB6 کار میکنم و دی ال الی میخواهم که در سی پلاس پلاس نوشته شده باشد که این کار را انجام دهد و من از این دی ال ال در VB6 استفاده کنم .
من از سی پلاس پلاس زیاد سردرنمیآورم به همین خاطر از دوستان این قسمت درخواست چنین کدی را کرده ام .

C++Lover
دوشنبه 24 مرداد 1384, 11:55 صبح
دوست عزیز شما باید در ابتدا یک Bitmap handle از کنترل مورد نظرتان بدست آورید و سپس با استفاده از تابع GetDIBits یک بلاک از پیکسلهای بیت مپ مورد نظرتان ایجاد کنید سپس عملیات را مستقیما روی این بلاک حافظه اجرا کنید و سپس با استفاده از تابع SetDIBits این بلاک را دوباره به بیتمپ خودتان منتقل کنید.
نکته این که این عملیات یعنی گرفتن بلاک و تغییرات از سرعت بالایی برخوردار است و فکر کنم نیاز شما را برطرف کند.
در ضمن دو تابعی که معرفی کردم عضو Gdi32.dll می باشند.

(سیدشریفی)
دوشنبه 24 مرداد 1384, 15:45 عصر
اگر دقت کنید در پست قبلی نوشته ام
من از سی پلاس پلاس زیاد سردرنمیآورم به همین خاطر از دوستان این قسمت درخواست چنین کدی را کرده ام .

C++Lover
سه شنبه 25 مرداد 1384, 01:34 صبح
معادل همان چیزهایی که گفتم اینجا بصورت vb .net می آورم
البته من تا بحال با vb برنامه نویسی نکرده ام.
در ضمن خودتان هم باید کمی تلاش کنید.
من فقط تا همین حد می توانم کمک کنم.



Dim img As Bitmap
img = PictureBox1.Image()
Dim rect As Rectangle
rect.Height = img.Height
rect.Width = img.Width
Dim bmp As System.Drawing.Imaging.BitmapData
bmp = img.LockBits(rect, Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppArgb)
Dim ix, iy As Integer
For iy = 0 To bmp.Height
For ix = 0 To bmp.Width
bmp.Scan0 ???
Next
Next
img.UnlockBits(bmp)


برای استفاده از این کد باید استفاده از IntPtr را بلد باشد
بین حلقه ها مستقیما اعمال خود را روی حافظه انجام دهید.

(سیدشریفی)
دوشنبه 07 شهریور 1384, 08:36 صبح
نمیدونم چرا سوال منو متوجه نمیشید .
من این کد رو تو زبان ++C میخواهم .
من در بیسیک این کار را انجام داده ام ولی سرعت کار پایین است به همین خاطر میخواهم در ++C این کد نوشته شود و به صورت یک DLL تبدیل شود تا من بتوانم از این DLL در زبان VB6 استفاده کنم .
امیدوارم مشکل منو فهمیده باشید .
:عصبانی:
:گریه:

(سیدشریفی)
پنج شنبه 17 شهریور 1384, 09:26 صبح
کسی نبود جواب بده
بابا سوال من برای شما که ++C کار میکنید نباید خیلی سخت باشد .
لطفا جواب بدید .

bahjat
جمعه 18 شهریور 1384, 12:50 عصر
با سلام
دوست عزیز اگر نگران هزینه آن نیستی
با من تماس بگیر

Behzad_60@hotmail.com

quack
شنبه 19 شهریور 1384, 07:54 صبح
سلام
حل این مشکل احتیاجی به کار کردن با C++ نداره.
برای اینکه سرعت رو بالا ببری قبل از اینکه با دو تا For بخوای Pixel هات رو بخونی باید اول pic رو از کنترلت بیاری توی یک متغیر توی حافظه. من توی Delphi از کلاس TBitmap استفاده کردم جواب داد مشابه این کلاس در VB نمی دونم چیه می تونی توی بخش vb سوال کنی.

C++Lover
یک شنبه 20 شهریور 1384, 13:14 عصر
جناب شریفی عزیز لطفا اطلاعات کاملی در مورد کاری که می خواهی رو عکس انجام بدهی بده شاید بتوانم dll ای رو برات بنویسم.
...

(سیدشریفی)
دوشنبه 21 شهریور 1384, 11:18 صبح
در وحله اول از تمامی دوستانی که به سوال اینجانب جواب میدهند کمال تشکر را دارم .
جناب C++Lover من میخواهم با فراخوانی یک فایل BMP این برنامه از پیکسل سمت چپ بالا شروع به گرفتن رنگ پیکسل کرده و این کار را در همان سطر ادامه دهد و به سطر پایین ادامه پیداکند و در حین انجام این کار پیکسلهای با رنگ مشابه را شمرده و در آخر شماره رنگ و تعداد پیکسلهای آن رنگ را در فایلی قرار دهد .
من این کار را در VB6 به صورت زیر انجام داده ام و همچین کدی را در ++C که DLL باشد میخواهم .
همچنین فایلی را که از این کد ایجاد میشود در زیر ضمیمه کرده ام تا خوب متوجه شوید .



For MyK = 1 To 10000
MyAray(MyK) = -1
Next MyK

For MyK = 1 To 10000
MyArayColor(MyK) = 0
Next MyK

For MyJ = 0 To Picture1.ScaleHeight - 1
For MyI = 0 To Picture1.ScaleWidth - 1
For MyK = 1 To 10000
If GetPixel(Picture1.hDC, MyI, MyJ) = MyAray(MyK) Then
MyArayColor(MyK) = MyArayColor(MyK) + 1
Exit For
ElseIf MyAray(MyK) = -1 Then
MyArayColor(MyK) = MyArayColor(MyK) + 1
MyAray(MyK) = GetPixel(Picture1.hDC, MyI, MyJ)
Exit For
End If
Next MyK
If MyK = 10001 Then
Label1.Caption = "تعداد رنگ بیش از ده هزار"
GoTo Error
End If
Next MyI
Next MyJ

For MyK = 1 To 10000
If MyAray(MyK) = -1 Then Exit For
Next MyK

Label4.Caption = "تعداد رنگ" & str(MyK - 1)

Open App.Path & "\Map\Carpet.dat" For Output As #1
For MyI = 1 To 10000
Write #1, MyAray(MyI); MyArayColor(MyI)
Next MyI
Close #1

Error:

taze kar
دوشنبه 21 شهریور 1384, 13:07 عصر
سلام .

آقا این DLL که نوشتم روی سیستم قدیمی ما که سرعتش خوب بود .
2 تا تابع داره
تابع اول با نام SetHDC که یکی پارامتر داره و از نوی HDC و هیچی هم بر نمی گردونه .
تابع دوم با نام GetMyPixel که 2 تا پارامتر داره . هر دو از نوع int و اولی طول و دومی عرض نقطه مورد نظرت هست . و یک مقدار COLORREF هم بر میگردونه که رنگ همون پیکسل هست .
اول باید تابع اول رو فراخوانی کنی و بستر دستگاه رو مشخص کنی . فقط یک بار . و بعد نقطه مورد نظرت رو بخونی . البته این تابع از تمام منطقه پنجره یا ناحیه ای که فرستادی مختصات رو محاسبه میکنه . یعنی گوشه بالا سمت چپ مختصات 0و0 رو داره .

البته امیدوارم مشکلی رو که برو بچ فاکس دارن شما نداشته باشی . چون DLL هام توی C++ جواب میدن ولی توی فاکس نه .

موفق باشی .

(سیدشریفی)
سه شنبه 22 شهریور 1384, 09:55 صبح
جناب taze kar از DLL ای که گذاشتید ممنون .
ولی من در VB6 از توابع API برای این کار استفاده میکنم و سرعت پایین میباشد DLL شما نیز همینطور چون من برای پیدا کردن رنگ هر پیکسل باید این کار را از داخل برنامه VB6 انجام دهم باز سرعت کار پایین میباشد من میخواهم کاری را که در بالا توضیح دادم کاملا در داخل این DLL انجام شود تا کار سریعتر انجام گیرد .

بهرحال از جوابی که دادید ممنون .

(سیدشریفی)
چهارشنبه 23 شهریور 1384, 09:08 صبح
جناب C++Lover منتظر جوابتان هستم

C++Lover
یک شنبه 03 مهر 1384, 00:45 صبح
ُسلام.
بیا این هم یه dll که یه تابع Export داره به نام ColorEnum که پارامتر اولش یک HBITMAP و پارامتر دومش یه رشته unicode که مسیر و نام فایل رو مشخص می کنه. مقدار برگشتی تابع هم تعداد رنگهای موجود توی bitmap است.
این تابع همان کاری که شما خواستید روی HBITMAP انجام می ده و خروجی رو توی فایلی که در پارامتر دوم معرفی کردید می ریزه.
محدودیتی برای تعداد رنگ وجود نداره اما اگه تعداد رنگهای استفاده شده بیشتر از 0xffff بشه کند عمل می کنه.
چون وقتم کمه این تابع رو با استفاده از STL نوشتم بنابراین زیاد سریع نیست به هر حال اگه مشکلتونو حل نکرد و احساس کردید خیلی کنده بگید تا اگه وقت کردم شاید بشه کمی سریعترش کرد.

(سیدشریفی)
یک شنبه 03 مهر 1384, 07:12 صبح
جناب C++Lover از وقتی که برای این کار گذاشتید ممنون
من این فایل را امتحان میکنم و نتیجه آن را برایتان مینویسم
باز هم ممنون

seyedof
یک شنبه 03 مهر 1384, 09:00 صبح
سلام
خواندن مستقیم از DDB ها کند است. برای عملیات روی تصویر با سرعت بالا، باید از DIB استفاده کنید. برای تبدیل DDB به DIB باید از تابع GetDIBits استفاده کنید.
ممنون علی

C++Lover
یک شنبه 03 مهر 1384, 12:00 عصر
جناب seyedof عزیز من هم دقیقا از GetDIBits استفاده کردم و مستقیما روی حافظه کار کردم.
اما مشکل کار از آنجاست که ممکن است یک Bitmap از تعداد حداکثر 0xffffffff رنگ استفاده کرده باشد که برای نگهداری و مدیریت این تعداد به آرایه ای 32 بیتی و با تعداد اندیس 0xffffffff نیاز است.
من از کلاس vector از STL استفاده کردم که باز هم این عملیات کند صورت می گیرد.
و چون از Binary search استفاده کردم الزاما باید عناصر رنگ به صورت sort شده در vector قرار گیرند.
مثلا فرض کنید که بعد از پیدا کردن تعداد 30000 رنگ ما یک رنگ که باید در مکان 2 آرایه قرار گیرد پیدا کرده ایم بنابراین vector تمامی عناصرش را از عنصر 2 به بعد به جلو shift داده و جا برای عنصر جدید باز می کند.
همچنین فرض کنید ما تعداد 100000 رنگ در vector ذخیره کرده ایم حال یک رنگ پیدا کرده ایم که باید در vector جایش را پیدا کنیم می بینید که همه این عملیات بسیار وقت گیر است.

به هر حال من راه حل بهتری پیدا نکردم اگر چه هنوز در حال تلاشم شاید راه بهتری پیدا کنم.
در صورتی که راه بهتری سراغ دارید ممنون می شوم من را هم در جریان بگذارید.

C++Lover
دوشنبه 04 مهر 1384, 01:50 صبح
سلام بیا این هم یه version جدید از همون dll ولی این بار حدودا 20 برابر سریعتر از قبلیه.
این دفعه از کلاس map از STL که از همون binary tree خودمون استفاده می کنه استفاده کردم.
البته اگه خودم یه binary tree منحصرا برای اینکار می نوشتم مسلما کد مقداری سریعتر هم میشد اما نسبت افزایش سرعت به زمان نوشتن کد نمی ارزه.
اگه راه جدیدی برای سریعتر کردن این DLL به ذهنم رسید و وقت کردم باز هم سریعترش می کنم.

(سیدشریفی)
دوشنبه 04 مهر 1384, 09:46 صبح
جناب C++Lover من نتوانستم از این DLL استفاده کنم
من نمیتونم این DLL را از طریق منوی References وارد پروژه بکنم لطفا راهنمایی کنید

C++Lover
دوشنبه 04 مهر 1384, 18:10 عصر
از vb اطلاعات چندانی ندارم.
من دقیقا نمی دونم چطوری میشه تو VB از یه DLL معمولی استفاده کرد اما مسلما میشه از com object ها استفاده کرد این dll رو براتون نوشتم که یه com object هستش میتونی مثل قبل ازش reference بگیرید و توی برنامه تان استفاده کنید.
من خودم دست و پا شکسته این کار رو با vb2005 انجام دادم البته vb2005 بر پایه net. هستش ولی vb6 نه خلاصه کلی با هم فرق دارند.
برای اجرا این کارها رو انجام بده.
ابتدا dll رو تو command prompt با استفاده از دستور زیر register کنید


regsvr32 ColorTbl.dll


بعد تو پروژه یه reference از روی dll بگیر.
کدی رو که تو vb2005 نوشتم برات می زارم شاید چیزی ازش سر در بیاری.
یادتون باشه پارامتر اول همون HBITMAP قبلیه ولی به خاطر محدودیتهای com object ها و بعضی زبانها این پارامتر رو به صورت INT64 نوشتمش که شما باید HBITMAP رو به INT64 تبدیل کنید و به تابع بفرستی.


Dim colort As GLSColorTblClass = New ColorTblLib.GLSColorTblClass
Dim bmp As Bitmap = New Bitmap(PictureBox1.Image)
colort.EnumColors(bmp.GetHbitmap.ToInt64, "file1.clr")

موفق باشی.

(سیدشریفی)
سه شنبه 05 مهر 1384, 16:29 عصر
دوست عزیز باز هم از وقتی که برای این کار صرف میکنید ممنون

این فایل را امتحان کرده و نتیجه را به اطلاع شما میرسانم