OpenCV هي مكتبة لها تاريخ من التطوير المستمر منذ 20 عامًا. العمر الذي تبدأ فيه الحفر في نفسك ، وتبحث عن وجهة. هل هناك أي مشاريع بناءً عليه جعلت حياة شخص ما أفضل ، شخص أكثر سعادة؟ يمكنك أن تفعل ذلك بنفسك؟ أبحث عن الإجابات والرغبة في اكتشاف وحدات OpenCV غير المعروفة سابقًا ، أريد إنشاء تطبيقات "تعمل بشكل جميل" - بحيث يكون هناك في البداية "واو" وعندها فقط تقول "أوه نعم ، إنها رؤية للكمبيوتر".
كان حق المقال الأول تجربة لنقل أنماط الفنانين العالميين في التصوير الفوتوغرافي. سوف تتعلم من المقال ما هو جوهر الإجراء وحول OpenCV.js الجديد نسبيًا - إصدار JavaScript من مكتبة OpenCV.

نقل النمط
سوف يغفر لي معارضو التعلم الآلي ، ولكن العنصر الرئيسي في مقال اليوم سيكون شبكة تلافيفية عميقة. لأنه يعمل. لا توجد طريقة لتدريب الشبكات العصبية في OpenCV ، ولكن يمكنك تشغيل الطرز الموجودة. سوف نستخدم شبكة CycleGAN المدربة مسبقًا. يقدم المؤلفون ، الذين يشعرون بالامتنان الشديد ، تنزيل مجاني للشبكات التي تحول صور التفاح إلى برتقال ، والخيول إلى الحمير الوحشية ، وصور الأقمار الصناعية إلى الخرائط ، والصور الشتوية إلى الصور الصيفية ، وأكثر من ذلك بكثير. علاوة على ذلك ، يتيح لك إجراء التدريب على الشبكة أن يكون لديك نموذجان للمولد يعملان في كلا الاتجاهين في وقت واحد. وهذا هو ، من خلال تدريس تحويل فصل الشتاء إلى فصل الصيف ، سوف تحصل على نموذج لطلاء المناظر الطبيعية في فصل الشتاء في الصور الصيفية. عرض فريد يستحيل رفضه.
في مثالنا ، نأخذ النماذج التي تحول الصور إلى لوحات للفنانين. وهي فنسنت فان جوخ ، كلود مونيه ، بول سيزان أو في النوع بأكمله من المطبوعات اليابانية Ukiyo-e. وهذا هو ، سيكون لدينا أربع شبكات منفصلة تحت تصرفنا. تجدر الإشارة إلى أنه بالنسبة لتدريب كل منهم ، لم يتم استخدام صورة واحدة للفنان ، ولكن جمهورًا كاملاً ، وبالتالي حاول المؤلفون تدريب الشبكة العصبية ليس لتغيير أسلوب عمل واحد ، ولكن ، كما كان ، لتبني أسلوب الكتابة.
Opencv.js
OpenCV هي مكتبة تم تطويرها في C ++ ، بينما بالنسبة لمعظم وظائفها ، هناك إمكانية لإنشاء مغلفات تلقائية تستدعي الأساليب الأصلية. رسميا ، يتم دعم مغلفات لغتي بايثون وجافا. بالإضافة إلى ذلك ، هناك حلول مخصصة لـ Go و PHP . إذا كانت لديك خبرة في استخدام اللغات الأخرى ، فسيكون من الرائع معرفة أي منها وبفضل جهودهم.
OpenCV.js هو مشروع اكتسب الحق في الحياة بفضل برنامج Google Summer of Code في عام 2017. بالمناسبة ، بمجرد إنشاء وحدة التعلم العميق OpenCV نفسها وتحسينها بشكل كبير في إطارها. على عكس اللغات الأخرى ، فإن OpenCV.js في الوقت الحالي ليس عبارة عن مجموعة من الطرق الأصلية في جافا سكريبت ، ولكن عبارة عن مجموعة كاملة تستخدم Emscripten باستخدام LLVM و Clang. يسمح لك بإنشاء ملف من تطبيق C أو C ++ أو المكتبة .js
التي يمكن تشغيلها ، على سبيل المثال ، في المستعرض.
على سبيل المثال ،
#include <iostream> int main(int argc, char** argv) { std::cout << "Hello, world!" << std::endl; return 0; }
تجميع في asm.js
emcc main.cpp -s WASM=0 -o main.js
وتحميل:
<!DOCTYPE html> <html> <head> <script src="main.js" type="text/javascript"></script> </head> </html>

يمكنك توصيل OpenCV.js بمشروعك على النحو التالي (الإنشاء الليلي):
<script src="https://docs.opencv.org/master/opencv.js" type="text/javascript"></script>
قد تكون مكتبة إضافية لقراءة الصور ، تعمل مع الكاميرا وأشياء أخرى ، والتي تتم كتابتها يدويًا في JavaScript ، مفيدة أيضًا:
<script src="https://docs.opencv.org/master/utils.js" type="text/javascript"></script>
تحميل الصور
يمكن قراءة الصور في OpenCV.js من عناصر مثل canvas
أو img
. هذا يعني أن تنزيل ملفات الصور مباشرة إليها يظل مهمة المستخدم. للراحة ، تقوم الوظيفة الإضافية addFileInputHandler
بتحميل الصورة تلقائيًا إلى عنصر canvas
المرغوب عند تحديد صورة من القرص بنقرة زر واحدة.
var utils = new Utils(''); utils.addFileInputHandler('fileInput', 'canvasInput'); var img = cv.imread('canvasInput');
اين
<input type="file" id="fileInput" name="file" accept="image/*" /> <canvas id="canvasInput" ></canvas>
النقطة المهمة هي أن img
سيكون صورة RGBA بأربع قنوات ، والتي تختلف عن cv::imread
المعتاد ، الذي ينشئ صورة BGR. يجب أن يؤخذ ذلك في الاعتبار ، على سبيل المثال ، عند نقل الخوارزميات من لغات أخرى.
مع التقديم ، كل شيء بسيط - ما imshow
سوى الاتصال بـ imshow
id
canvas
المرغوبة (تتوقع RGB أو RGBA).
cv.imshow("canvasOutput", img);
خوارزمية
الخوارزمية الكاملة لمعالجة الصور هي إطلاق شبكة عصبية. لنفترض أن ما يحدث في الداخل لا يزال سحريًا ، نحتاج فقط إلى إعداد الإدخال الصحيح وتفسير التنبؤ بشكل صحيح (إخراج الشبكة).
تتلقى الشبكة الموضحة في هذا المثال موترًا رباعي الأبعاد له قيم float
في الفاصل الزمني [-1, 1]
. كل من الأبعاد ، حسب سرعة التغيير ، هو فهرس الصورة والقنوات والارتفاع والعرض. يسمى هذا التصميم NCHW ، ويسمى الموتر نفسه كائنًا كبيرًا ثنائيًا. تتمثل مهمة المعالجة المسبقة في تحويل صورة OpenCV ، والتي تكون شدتها متداخلة ، ولها فاصل زمني من القيم [0, 255]
النوع unsigned char
في نقطة NCHW ذات نطاق من القيم [-1, 1]
.

قطعة من نيجني نوفغورود الكرملين (كما يراها الشخص)

عرض معشق (كيف يخزن OpenCV)

عرض مستو (ما تحتاجه الشبكة)
كعملية ما بعد المعالجة ، سيكون من الضروري إجراء التحويلات العكسية: تقوم الشبكة بإرجاع blob NCHW مع القيم في الفاصل الزمني [-1, 1]
، والتي يجب إعادة تعبئتها في الصورة ، وتطبيعها إلى [0, 255]
وتحويلها إلى unsigned char
.
وبالتالي ، مع مراعاة جميع ميزات قراءة وكتابة صور OpenCV.js ، فإن الخطوات التالية آخذة في التبلور:
imread -> RGBA -> BGR [0, 255] -> NCHW [-1, 1] -> [] [] -> NCHW [-1, 1] -> RGB [0, 255] -> imshow
عند النظر إلى خط الأنابيب الناتج ، تثور أسئلة ، لماذا لا تستطيع الشبكة العمل فورًا على RGBA المتشابك وإرجاع RGB المتداخلة؟ لماذا هناك حاجة لتحويلات إضافية للتحول والتطبيع بالبكسل؟ الجواب هو أن الشبكة العصبية هي كائن رياضي يقوم بإجراء تحويلات على بيانات الإدخال الخاصة بتوزيع معين. في حالتنا ، تم تدريبها على تلقي البيانات في هذا النموذج ، وبالتالي ، للحصول على النتائج المرجوة ، من الضروري إعادة إنتاج المعالجة المسبقة التي استخدمها المؤلفون في التدريب.
التنفيذ
يتم تخزين الشبكة العصبية التي سنقوم بتشغيلها في شكل ملف ثنائي ، والذي يجب أولاً تحميله في نظام الملفات المحلي.
var net; var url = 'style_vangogh.t7'; utils.createFileFromUrl('style_vangogh.t7', url, () => { net = cv.readNet('style_vangogh.t7'); });
بالمناسبة ، url
كامل للملف. في هذه الحالة ، نقوم فقط بتحميل الملف بجانب صفحة HTML الحالية ، ولكن يمكنك استبداله بالمصدر الأصلي (في هذه الحالة ، قد يكون وقت التنزيل أطول).
قراءة صورة من canvas
والتحويل من RGBA إلى BGR:
var imgRGBA = cv.imread('canvasInput'); var imgBGR = new cv.Mat(imgRGBA.rows, imgRGBA.cols, cv.CV_8UC3); cv.cvtColor(imgRGBA, imgBGR, cv.COLOR_RGBA2BGR);
إنشاء blob 4D حيث تحول وظيفة blobFromImage
إلى float
بيانات float
باستخدام ثوابت التطبيع. ثم - إطلاق الشبكة.
var blob = cv.blobFromImage(imgBGR, 1.0 / 127.5,
يتم تحويل النتيجة مرة أخرى إلى صورة من النوع المطلوب والفاصل الزمني للقيم [0, 255]
في الوقت الحالي ، يتم إنشاء OpenCV.js في الوضع شبه التلقائي. بمعنى أنه ليس كل الوحدات النمطية والأساليب منها تتلقى التواقيع المقابلة في JavaScript. على سبيل المثال ، بالنسبة لوحدة dnn ، يتم تعريف قائمة الوظائف الصحيحة على النحو التالي:
dnn = {'dnn_Net': ['setInput', 'forward'], '': ['readNetFromCaffe', 'readNetFromTensorflow', 'readNetFromTorch', 'readNetFromDarknet', 'readNetFromONNX', 'readNet', 'blobFromImage']}
التحويل الأخير ، بتقسيم النقطة إلى ثلاث قنوات ثم دمجها في صورة ، في الواقع ، يمكن القيام به باستخدام طريقة واحدة من أسلوب imagesFromBlob
، والتي لم تتم إضافتها إلى القائمة أعلاه. ربما ستكون هذه هي مساهمتك الأولى في تطوير OpenCV؟ ؛)
الخاتمة
كإظهار ، قمت بإعداد صفحة على GitHub حيث يمكنك اختبار الكود الناتج: https://dkurtaev.imtqy.com/opencv4arts (تحذير! تنزيل شبكة بحجم 22 ميغابايت تقريبًا ، حفظ حركة المرور الخاصة بك. يوصى أيضًا بإعادة تحميل الصفحة لكل صورة جديدة ، وإلا فإن الجودة المعالجة اللاحقة مشوهة بقوة إلى حد ما). كن مستعدًا لعملية معالجة طويلة أو حاول تغيير حجم الصورة ، والتي ستكون النتيجة ، شريط تمرير.
أثناء العمل على المقال واختيار الصورة ذاتها التي ستصبح وجهها ، وجدت بطريق الخطأ صورة لصديقي ، والتي تصور الكرملين في مدينتنا ، وكل شيء قد تضافرت - جاءت باسم المقال وشعرت حينها فقط أنه ينبغي أن يكون الأمر كذلك. أقترح عليك تجربة التطبيق على صور من المكان المفضل لديك ، وربما أخبر شيئًا مثيرًا للاهتمام في التعليقات أو في رسالة شخصية.
مني - حقيقة ممتعة. يستخدم معظم سكان نيجني نوفغورود ومنطقة نيجني نوفغورود كلمة "الخروج" بمعنى كلمة "لائق" (ابحث عن مكان مجاني). على سبيل المثال ، السؤال "هل سنقوم بتنظيف سيارتك؟" يعني "هل لدينا مساحة كافية في سيارتك؟" ، ولكن ليس "هل يمكننا تنظيف سيارتك؟". عندما يأتي إلينا طلاب من مناطق أخرى للتدريب الداخلي في الصيف ، فإننا نحب أن نقول هذه الحقيقة - فالكثيرون فوجئوا بصدق.
روابط مفيدة