├── Arial-Unicode-Regular.ttf ├── LICENSE ├── README.md ├── codec.txt ├── codec_rctw.txt ├── data_gen.py ├── data_util.py ├── demo.py ├── docker ├── Dockerfile ├── README.md ├── build_docker.sh └── run_docker.sh ├── eval.py ├── images └── synth.png ├── models.py ├── net_utils.py ├── nms ├── .gitignore ├── Makefile ├── __init__.py ├── adaptor.cpp ├── include │ ├── clipper │ │ ├── clipper.cpp │ │ └── clipper.hpp │ └── pybind11 │ │ ├── attr.h │ │ ├── buffer_info.h │ │ ├── cast.h │ │ ├── chrono.h │ │ ├── common.h │ │ ├── complex.h │ │ ├── detail │ │ ├── class.h │ │ ├── common.h │ │ ├── descr.h │ │ ├── init.h │ │ ├── internals.h │ │ └── typeid.h │ │ ├── eigen.h │ │ ├── embed.h │ │ ├── eval.h │ │ ├── functional.h │ │ ├── iostream.h │ │ ├── numpy.h │ │ ├── operators.h │ │ ├── options.h │ │ ├── pybind11.h │ │ ├── pytypes.h │ │ ├── stl.h │ │ └── stl_bind.h └── nms.h ├── ocr_gen.py ├── ocr_test_utils.py ├── ocr_utils.py ├── sample_train_data ├── MLT │ ├── README.md │ ├── done │ │ ├── gt_img_5407.txt │ │ └── img_5407.jpg │ ├── icdar-2015-Ch4 │ │ └── Train │ │ │ ├── gt_img_784.txt │ │ │ └── img_784.jpg │ └── trainMLT.txt └── MLT_CROPS │ ├── gt.txt │ ├── word_118.png │ ├── word_119.png │ ├── word_120.png │ └── word_121.png ├── train.py └── train_ocr.py /Arial-Unicode-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichalBusta/E2E-MLT/fc79f9ab4c8c75c882fae12c399d1c5355bb8a1b/Arial-Unicode-Regular.ttf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2020, Michal Busta 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # E2E-MLT 2 | E2E-MLT - an Unconstrained End-to-End Method for Multi-Language Scene Text 3 | code base for: https://arxiv.org/abs/1801.09919 4 | 5 | 6 | 7 | ``` 8 | @@inproceedings{buvsta2018e2e, 9 | title={E2E-MLT-an unconstrained end-to-end method for multi-language scene text}, 10 | author={Bu{\v{s}}ta, Michal and Patel, Yash and Matas, Jiri}, 11 | booktitle={Asian Conference on Computer Vision}, 12 | pages={127--143}, 13 | year={2018}, 14 | organization={Springer} 15 | } 16 | ``` 17 | 18 | 19 | ## Requirements 20 | 21 | - python3.x with 22 | - opencv-python 23 | - pytorch 0.4.1 24 | - torchvision 25 | - warp-ctc (https://github.com/SeanNaren/warp-ctc/) 26 | 27 | ## Pretrained Models 28 | 29 | [e2e-mlt](http://ptak.felk.cvut.cz/public_datasets/SyntText/e2e-mlt.h5), [e2e-mlt-rctw](http://ptak.felk.cvut.cz/public_datasets/SyntText/e2e-mltrctw.h5) 30 | 31 | ``` 32 | wget http://ptak.felk.cvut.cz/public_datasets/SyntText/e2e-mlt.h5 33 | ``` 34 | 35 | ## Running Demo 36 | 37 | ``` 38 | python3 demo.py -model=e2e-mlt.h5 39 | ``` 40 | 41 | ## Data 42 | 43 | - [ICDAR-MLT 2017 Dataset](http://rrc.cvc.uab.es/?ch=8&com=introduction) 44 | - [ICDAR 2015 Dataset](http://rrc.cvc.uab.es/?ch=4&com=introduction) 45 | - [RCTW-17](http://mclab.eic.hust.edu.cn/icdar2017chinese/) 46 | - Synthetic MLT Data ([Arabic](http://ptak.felk.cvut.cz/public_datasets/SyntText/Arabic.zip), [Bangla](http://ptak.felk.cvut.cz/public_datasets/SyntText/Bangla.zip), [Chinese](http://ptak.felk.cvut.cz/public_datasets/SyntText/Chinese.zip), [Japanese](http://ptak.felk.cvut.cz/public_datasets/SyntText/Japanese.zip), [Korean](http://ptak.felk.cvut.cz/public_datasets/SyntText/Korean.zip), [Latin](http://ptak.felk.cvut.cz/public_datasets/SyntText/Latin.zip), [Hindi](http://ptak.felk.cvut.cz/public_datasets/SyntText/Hindi.zip) ) 47 | - and converted GT to icdar MLT format (see: http://rrc.cvc.uab.es/?ch=8&com=tasks) 48 | ([Arabic](http://ptak.felk.cvut.cz/public_datasets/SyntText/Arabic_gt.zip), [Bangla](http://ptak.felk.cvut.cz/public_datasets/SyntText/Bangla_gt.zip), [Chinese](http://ptak.felk.cvut.cz/public_datasets/SyntText/Chinese_gt.zip), [Japanese](http://ptak.felk.cvut.cz/public_datasets/SyntText/Japanese_gt.zip), [Korean](http://ptak.felk.cvut.cz/public_datasets/SyntText/Korean_gt.zip), [Latin](http://ptak.felk.cvut.cz/public_datasets/SyntText/Latin_gt.zip), [Hindi](http://ptak.felk.cvut.cz/public_datasets/SyntText/Hindi_gt.zip) ) 49 | 50 | 51 | ![MLT SynthSet](images/synth.png) 52 | 53 | Synthetic text has been generated using [Synthetic Data for Text Localisation in Natural Images](https://github.com/ankush-me/SynthText), with minor changes for Arabic and Bangla script rendering. 54 | 55 | What we have found useful: 56 | - for generating Arabic Scene Text: https://github.com/mpcabd/python-arabic-reshaper 57 | - for generating Bangla Scene Text: PyQt4 58 | - having somebody who can read non-latin scripts: we would like to thank Ali Anas for reviewing generated Arabic scene text. 59 | 60 | 61 | ## Training 62 | 63 | ``` 64 | python3 train.py -train_list=sample_train_data/MLT/trainMLT.txt -batch_size=8 -num_readers=5 -debug=0 -input_size=512 -ocr_batch_size=256 -ocr_feed_list=sample_train_data/MLT_CROPS/gt.txt 65 | ``` 66 | 67 | ## Acknowledgments 68 | 69 | Code borrows from [EAST](https://github.com/argman/EAST) and [DeepTextSpotter](https://github.com/MichalBusta/DeepTextSpotter) 70 | 71 | -------------------------------------------------------------------------------- /codec.txt: -------------------------------------------------------------------------------- 1 | !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„†‡ˆŠ‹ŒŽ‘’“”•–˜™šœž ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāăąĆćČčĎĐđēĖęĚěğħīıŁłńňŌōŏőŒœřŚśŞşŠšťūŷŸźżŽžƒǔǘǧșɯʒʼʾʿˆˇˉ˘˚˜˝̀́̃̈;ΈΏΑΔΛΟΣΩάέαβδεηθικλμνοπρςστφωόϟЃЄАБВГДЕЗИЙКЛМНОПРСТУФХЦЧШЫЬЭЮЯабвгдежзийклмнопрстуфхчшыьэяёєїֳאגהוטיכלנרשת،؛؟ءآأؤإئابةتثجحخدذرزسشصضطظعغـفقكلمنهوىيًٌٍَُِّْ٠١٢٣٤٥٦٧٨٩٫٬ڤڥڧڨڭࠍࠥࠦएकदनभमलशसािीुे्।॥ঁংঃঅআইঈউঊঋএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ািীুূৃেৈোৌ্ৎৗড়ঢ়য়০১২৩৪৫৬৭৮৯ৰ৷৺ఇᄂᄃᄉᄊᄋᄏᄑ하ᅥᅧᅳᅵḤḥṃṇṛṠṣẒễệừὋῖ‌‎‐‑‒–—―‖‘’‚“”„‟†‡•‥…‧‬‭‰′″‹›※⁄₂₣₤₩€℃ℓ™⅛←→↔⇐⇒⇔∂∆∇∑−√∣∫∼≈≤≥〈①②③─╚╢╩▁■□▪▲△▶►▼▽◆◇◊○●◙★☺☻♠♣♥♦♬✤❤➔➜ 、。々〇〈〉《》「」『』【】〓〔〕ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろわをんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヱヲンヴヵヶ・ーㆍ㈜㎞㎡㡢㨲㩠㩡㩥㩬一丁七万丈三上下不与丑专且世丘丙业丛东丝両丢两严並丧个中丰串临丸丹为主丼丽举乃久么义之乌乍乎乏乐乔乗乘乙九乞也习乡书买乱乳乾亀了予争事二亍于亏亐云互五井亚些亜亡交亥亦产亨享京亭亮亲亵人亿什仁仅仆仇今介仍从仏仑仓仔仕他仗付仙代令以仪们仮仰仲件价任份仿企伊伍伎伏伐休众优伙会伝伞伟传伤伦伪伯估伴伶伸伺似伽但位低住佐佑体何余佛作你佣佯佰佳併佶佼使侄例侍侖供依侠価侣侥侦侧侨侯侵侶便係促俄俊俏俐俗俘保俞信俩俭修俯俱俳俸俺倉個倍倒候倚借倡倣値倦倫倶债值倾假偉偏做停健側偵偶偷偽偿傅傍傘備储催傭傲債傷傻傾僅働像僑僕僚僧僵價儀億儒償優儲儿允元兄充兆先光克免児兑兒兔党兜入內全兩兪八公六兰共关兴兵其具典兹养兼冀内円冈冊册再冒冕冗写军农冠冢冤冥冬冯冰冲决况冷冻冽净凄准凉凌凍减凑凖凝凞几凡凤処凭凯凰凶凸凹出击函凿刀刁分切刊刑划列刘则刚创初删判別利刪别刮到制刷券刹刺刻剁剂剃則削前剑剔剖剛剣剤剥剧剩剪副剰割創劃劇劉劑力劝办功加务劣动助努劫励劲劳労劵効劾势勃勇勉勋勒動勘務勝募勢勤勧勲勳勾勿匀匂包匈化北匙匠匡匣匪匹区医匾匿區十千升午半华协卑卒卓協单卖南単博卜卞占卡卢卧卫卯印危即却卵卷卸卿厂厄厅历厉压厌厕厘厚原厢厥厦厨厳去县参參又叉及友双反収发取受变叙叛叠口古句另叩只叫召叭可台叱史右叶号司叹吁吃各合吉吊同名后吏吐向吓吕吗君吞否吧吨含听启吳吴吵吸吹吻呀呂呆呈呉告呐呑呕员呜呢周味呼命咀和咎咐咒咖咤咨咫咬咲咳咸咽哀品哇哈哉响哎哑哗員哥哨哪哭哲哺哽唆唇唉唐唤售唯唱唸唾啄商啊問啓啟啡啤啥啦啼喀喂善喆喇喉喊喘喚喜喝喧喪喫單喰営喷喻嗓嗜嗣嗤嗯嗽嘆嘉嘘嘛嘱嘲嘴嘿噌噗噛噢噤器噩噪噴嚴嚼囊囚四回因团団园困囲図围固国图圃圆圈國圍圏園圓圖團土圣圧在圭地圳场圾址坂均坊坎坏坐坑块坚坛坝坞坠坡坤坦坪坰垂垃垄型垒垚垢垣垫埃埈埋城埙域埠執培基堂堅堆堡堤堪報場堵塊塌塑塔塗塘塚塞塩填塾境墅墓増墙墜增墟墨墳壁壇壊壌壎壞壤士壬壮声壱売壳壹壽处备変复夏夕外多夜够夢大天太夫夭央失头夷夸夹夺奇奈奉奋奎奏契奔奖套奠奥奧奨奪奬奭奮女奴奶奸她好如妃妄妆妇妈妊妍妒妙妝妥妨妮妹妻姃姆姉姊始姐姑姓委姙姚姜姦姨姫姬姸姻姿威娅娇娘娜娠娥娩娯娱娶婆婉婊婚婦婴婷婿媒媛媲媳嫁嫉嫌嬉嬌嬪子孔孕字存孙孜孝孟季孤学孩孫孵學宁它宅宇守安宋完宏宗官宙定宛宜宝实実宠审客宣室宪宫宮宰害宴宵家容宽宾宿寂寄寅密富寒寓寛寝察寡寢寥實寧寨審寫寬寮寵寶寸对寺寻导対寿封専射将將專尊尋對導小少尔尖尘尙尚尝尤尬就尴尸尹尺尻尼尽尾尿局屁层居屈届屋屎屏屑展属屠層履屯山屿岁岌岐岔岖岗岘岛岡岩岫岭岳岷岸峙峠峡峨峭峯峰峴島峻崇崎崔崖崗崛崩崭嵌嵩嶺嶽巌巖川州巡巢巣工左巧巨巩巫差己已巴巷巻巾币市布帅帆师希帐帕帖帘帚帝带師席帮帯帰帳帷常帽幅幇幌幔幕幡幢幣干平年并幸幹幻幼幽幾广庁広庄庆庇床序库应底店庙庚府庞废度座庫庭庵庶康庸廃廉廊廓廖廛廟延廷建廻开弁异弃弄弊式弐弓弔引弗弘弛弟张弥弦弧弯弱張強弹强弾归当录形彦彩彫彬彭彰影彷役彻彼彿往征径待很徊律後徐徑徒従得徘御復循微徳徴徵德徹心必忆忌忍志忘忙応忠忧快念忽怀态怅怎怒怕怖怜思怠怡急怦性怨怪怯总恃恋恍恐恒恕恙恢恣恤恥恨恩恭息恰恳恵恶恻恼悉悔悖悚悟悠患悦您悩悪悬悲悳悽情惆惇惊惋惑惕惗惚惜惟惠惡惣惧惨惩惫惯惱想惶惹惺愁愈愉意愚愛感愤愧愿慈態慌慎慕慢慣慧慨慮慰慶慷憂憎憤憧憨憩憫憬憲憶憺憾懂懇懈應懐懒懦懲懸戈戏成我戒或战戚戦截戰戴戶户戸戻房所扁扇扉手才扎扑打扔払托扣执扩扪扫扬扭扮扰扱扳扶批找承技抉把抑抒抓投抖抗折抚抛抜択抢护报披抱抵抹押抽抿担拆拉拌拍拎拒拓拔拖拘拙招拜拝拟拠拡拢拥拦拨择括拭拯拳拶拷拼拾拿持挂指按挑挖挙挚挛挝挟挠挡挣挤挥挨挪挫振挽挿捆捉捍捏捐捕捜损捡换捧捨据捷捻掀掃授掉掌掏掐排掘掛掠採探接控推掩措掲掺揃揄揆揉描提插揚換握揭揮援揶揺揽搁搅損搏搓搖搜搞搬搭携搾摁摂摄摆摇摔摘摧摩摯摸撃撑撒撞撤撩播撮撰撲擁擅操擎據擢擦攀攒攣支收改攻放政故效敌敍敎敏救敗教敛敞敢散敦敬数敲整敵敷數斂文斉斋斌斎斐斑斗料斜斟斡斤斥斧斩斬断斯新方於施旁旅旋旌族旗无既日旦旧旨早旬旭时旷旺旻旼旿昂昆昇昉昊昌明昏易昔星映春昧昨昭是昼显晁時晃晋晓晚晟晤晦晨晩晫普景晰晴晶智晾暁暂暇暈暑暖暗暦暨暫暮暴暻曉曖曙曜曝曲更書曹曺曼曽曾替最會月有朋服朔朗望朝期朦木未末本札术朱朴朵机朽杀杂权杆杉李杏材村杓杖杜杞束条来杨杭杯杰東松板极构枉析枓枕林枚果枝枠枢枪枫枯架枷枸柄柏某柑染柔柜柠查柯柱柳柴柵査柿栄栅标栈栋栏树栓栗校栩株样核根格栽桁桂桃框案桌桐桑桓桜档桥桦桶梁梅梗條梢梦梨梭梯械梵检棄棉棋棍棒棕棚棟森棱棲棵棺椅植椎椒検椭椿楊楕楚業極楷楼楽概榆榛榜榧榨榭榮榻構槍様槛槟槳槽槿樂樓標樟模樣権横樵樹樺樽橇橋橘橙機橡橫橱檀檐檔檢檬櫓欄權欠次欢欣欧欲欺款歉歌歎歓歡止正此步武歧歩歪歯歳歴歹死殃殆殉殊残殖殴段殷殺殿毀毁毅毋母毎每毒比毕毙毛毫毯氏民氓气気氚氛氟氢氣氧氩水氷永氾汀汁求汇汉汎汗汚汝江池污汤汪汰汲汴汶汹決汽沁沂沃沈沉沌沐沒沖沙沟没沢沦沧沪沫河油治沼沾沿況泂泄泉泊泌法泛泡波泣泥注泪泯泰泳泵泼泽泾洁洋洒洗洙洛洞津洪洲洵活洼派流浄浅浆测济浏浑浓浙浚浜浣浦浩浪浮浴海浸涂消涉涌涓涙涛涜涡涤润涧涨涪涯液涵涼淀淆淇淋淌淑淘淞淡淤淫深淳淵混淸淹淺添清渇済渉渊渋渎渐渓渔渗減渝渠渡渣渤温測港渲渴游渾湖湘湧湯湾湿満溃溅溉溌源準溜溝溢溪溫溯溶滅滉滋滑滓滔滕滚滞满滥滦滨滩滲滴滿漁漂漆漏漓演漠漢漫漬漱潍潔潘潜潤潭潮澄澈澗澜澡澤澱澳激濁濃濟濡濤濩濫濬濯瀑瀕瀚瀬灌灘灣火灭灯灰灵灸災灾灿炅炉炊炎炕炙炫炬炭炮炯炳炸点為炼烁烂烈烏烘烟烤烦烧烨烫热烯烹焉焊焕焖焘焙焚無焦焰然焼煉煌煎煕煙煤煥照煮煽熄熊熏熙熟熨熬熱熹熾燁燃燒燕營燥燦燮燾爀爆爐爨爪爬爱爲爵父爷爸爺爽片版牌牒牙牛牡牢牧物牲牵特牺牽犠犧犬犯状犷犹狀狂狐狗狙狡狩独狭狮狱狸狼猕猛猜猟猥猪猫献猴猶猿獄獐獨獲玄率玉王玖玛玥玩玫环现玲玹玺玻珈珉珊珍珐珑珞珠珪班現球琅理琇琏琐琦琲琴琼瑕瑛瑜瑞瑟瑩瑰瑶璃璉璋璜璟璧環璹璽瓊瓒瓚瓜瓠瓢瓣瓦瓮瓶瓷甕甘甙甚甜生產産用甩甫甬田由甲申电男町画畅界畏畑畔留畜畢略番畯異畳畵當畿疆疋疎疏疑疗疫疯疲疵疹疼疾病症痉痒痕痙痛痢痪痫痰痴痹瘁瘍瘙瘦瘪瘫瘾療癇癌癒癖癫癲発登發白百皂的皆皇皋皓皙皮皱皿盂盆盈益盏盐监盒盖盗盘盛盟監盤盧目盯盲直相盼盾省眈眉看県眞真眠眶眺眼眾着睁睐睛睡督睦睫睹瞄瞑瞒瞞瞩瞪瞬瞭瞰瞻矛矢矣知矫短矮矯石矶矿码砂砍研砖砥砲破砸础硅硏硕硝硬确硯碁碌碍碎碑碗碘碟碧碩碰碱碳確磁磋磨磻礎示礼社祀祈祉祐祖祚祜祝神祠祥票祭祯祷祸禁禄禅禍禎福禧禪禹离禽禾秀私秉秋种科秒秕秘租秦秩积称移稀稅程稍税稚稜稣種稱稲稳稷稻稼稽稿穀穂穆積穏穫穴究穷空穿突窃窄窍窓窗窝窟窮窺窿立站竜竞竟章竣童竭端競竹竿笋笑笔笛符笨第笹笼筆等筋筏筑筒答策筝筹签简箇算管箫箭箱節範篆篇築簡簿籍米类粉粋粒粗粘粛粥粧粪粮粲粹精糀糊糕糖糙糟糧糯糸系糾紀約紅紆紊紋納紐純紗紙級紛素紡索紧紫累細紹紺終組経結絞絡給絨統絵絶絹經継続綜綠維綱網綻綿緊総緑緒緖線締編緩緯練緻縁縄縛縞縣縦縫縮縱總績繁繊織繕繰纉續纏纠红纤约级纪纫纬纭纯纱纲纳纵纶纷纸纹纺纽线绀练组细织终绊绌绍绎经绑绒结绕绘给络绝绞统继绩绪续绰绳维绵绸综绽绿缄缆缓缔编缘缚缝缟缠缩缬缴缶缸缺罄罐网罔罕罗罚罠罢罩罪置罰署罵罹羁羅羈羊美羞羡群羨義羲羽翁翌翎習翔翕翘翠翩翰翱翻翼耀老考者而耍耐耕耗耙耳耶耻耽聂聆聊职联聖聘聚聞聪聴聶職肃肇肉肌肖肘肚肝肠股肢肤肥肩肪肯育肴肺肿胀胁胃胆背胎胖胚胜胞胡胤胧胳胴胶胸胺能脂脅脆脇脈脉脊脏脐脑脚脫脱脳脸脹脾腊腋腌腐腑腔腕腦腫腰腱腸腹腺腻腾腿膀膊膏膚膜膝膠膨膳膺臀臂臓臣臨自臭至致臺臻臼舀舅舆與興舉舊舌舍舎舒舗舜舞舟航舫般舰舱舵舶船艇艘艦良艰色艳艺艾节芉芋芒芙芝芦芪芬芭芯花芳芸芽苇苍苏苑苒苗苛苟若苦英苹苺茂范茄茅茎茗茜茨茫茵茶茸荆草荏荐荒荔荚荞荡荣荧荫药荷荼莅莉莊莎莓莠莫莱莲获莽菀菅菇菉菌菓菖菜菩華菱菲菸萄萌萎营萧萨萬落葉著葛葡董葦葫葬葱葵葺蒂蒋蒙蒜蒲蒸蒼蒾蒿蓄蓉蓋蓝蓬蓮蔑蔓蔗蔚蔡蔦蔬蔵蔷蔽蕉蕊蕎蕓蕨蕴蕾薄薇薙薛薦薩薪薫薬薯薰藍藏藤藥藻藿蘆蘇蘑蘭虎虏虐虑處虚虜號虫虹虽虾蚀蚁蚂蚕蛀蛄蛇蛋蛍蛙蛛蛟蛮蛹蜀蜂蜃蜘蜜蝉蝙蝠蝶螂融螢螺蟑蟾蠡蠢蠵蠶血衅衆行衍術衔街衛衝衡衣补表衫衬衰衷衿袁袂袋袍袒袖袜被袭袱裁裂装裏裔裕補裝裤裴裵裸裹製裾複褐褒褡褥褪襟襲西要覆覇見規視覚覧親観覺覽觀见观规视览觉觊觎觑角解触言訂計討訓託記訟訣訪設許訳訴診証詐評詞試詩詫詭詰話該詳詹誅誇誉誌認誓誕誘語誠誡誤說説読誰課調談請論諦諮諷諸諾謀謄謙講謝謡謬謳謹證識譚譜警議譲護讀讃變讐计订认讥讧讨让训议讯记讲讶许论讼讽设访诀证评诅识诈诉诊词译试诗诙诚话诞诡询该详诫诬语误诱说诵请诸诺读课谁调谅谈谊谋谍谎谐谓谜谢谣谦谨谬谭谱谴谷豁豆豊豚象豪豫貌貝貞負財貢貧貨販貫責貯貴買貸費貼貿賀賃資賊賑賓賛賜賞賠賢賦質賭購贅贈贓贝贞负贡财责贤败账货质贩贪贫贬购贯贴贵贷贸费贺贼贿赁资赋赌赎赏赐赔赖赚赛赞赠赢赤赦赫走赴赵赶起趁超越趋趙趣足趾跃跆跌跏跑距跟跡跤跨路跳践跻踊踏踝踢踩踪踱踵蹄蹈蹴躍身躬躲躺車軌軍軒軟転軫軸軽較載輌輔輝輩輪輸輿轄轉轟车轨轩转轮软轰轴轻载轿较辅辆辈辉辐辑输辖辙辛辜辞辟辣辨辩辫辭辰辱農边辺辻込辽达辿迁迂迄迅过迈迎运近返还这进远违连迟迪迫述迴迷迹追退送适逃逅逆选逊透逐递途逗這通逝速造逢連逮週進逸逹逻逼逾遂遅遇遊運遍過道達違遗遜遠遡遣遥適遭遮遵選遺遼避邀邁邂還邊邑那邦邪邮邱邵邸邻郁郊郎郑郝郞郡部郭郵郷都鄂鄉鄙鄭酉酋酌配酎酒酔酗酢酪酬酰酱酵酷酸酿醇醉醋醍醐醒醛醜醴醸采釈释釋里重野量金釘釜針釣鈍鈞鈺鉄鉉鉛鉢鉱鉴銀銃銅銓銖銘銭銷鋒鋪鋭鋼錄錐錞錠錦錫錬錯録鍊鍋鍵鍼鍾鎌鎔鎖鎬鎭鎮鏞鏡鐘鐵鐸鑑鑫针钉钓钙钚钛钝钞钟钠钢钧钩钮钰钱钵钻钾铀铁铃铅铉铜铝铢铨铬铭铱银铺链销锁锂锅锈锋锐错锡锣锤锦键锯锻镁镇镍镐镕镛镜镳镶長长門閉開閏閑間閔閠関閣閥閲闇闊闕闘關门闪闭问闯闰闲间闵闷闸闹闻闽阁阅阐阔阙阜队阪阱防阳阴阵阶阻阿陀附际陆陈陋陌降限陕陡院陣除陥陨险陪陰陳陵陶陷陸険陽隅隆隊階随隐隔隕隘隙際障隠隣隧隨險隱隶隷隻难雀雁雄雅集雇雉雌雑雕雙雛雜離難雨雪雰雲雳零雷電雾需霄霆震霉霊霍霏霓霜霞霧露霸霹靈靑青靓靖静靜非靠靡面革靴鞄鞋鞘鞠鞭韓韦韧韩音韵韻響頁頂頃項順須預頑頓領頭頴頻頼題額顔顕願類顧顯页顶项顺须顽顾顿颁颂预领颇颈频颔颖颗题颜额颠颤風风飓飘飙飚飛飞食飢飬飯飲飴飼飽飾餅養餌餐餓餘館饅饗饥饪饭饮饰饱饲饵饶饺饼饿馆馈首香馥馨馬馴駄駅駆駐駿騒験騰驗驚驪马驯驰驱驳驶驻驾驿骂骄骊验骏骑骗骚骤骨骸髓體高髙髪鬱鬼魁魂魄魅魏魔魚魯鮎鮨鮮鯵鰍鰐鱼鱿鲁鲍鲐鲜鲨鲹鳗鳥鳳鳴鴉鴨鴻鵡鶏鶴鷄鷹鷺鸟鸡鸣鸥鸦鸭鸿鹅鹊鹏鹤鹭鹰鹿麒麓麗麟麦麺麻黃黄黎黑黒默黙黨黯鼎鼓鼠鼻齋齐齢齿龄龈龋龍龙龜龟가각간갇갈갉감갑값갔강갖같갚개객갤갯갱걀걔거걱건걷걸검겁것겅겉게겐겔겠겡겨격겪견결겸겹겼경곁계고곡곤곧골곯곰곱곳공곶과곽관괄괌광괜괴굉교구국군굳굴굵굶굽굿궁궈권궐궜궤귀귓규균귤그극근글긁금급긋긍기긴길김깁깃깅깊까깎깐깔깜깝깡깥깨꺼꺾껄껌껍껏껐께껴꼇꼈꼬꼭꼴꼼꼽꽁꽂꽃꽉꽝꽤꾀꾜꾸꾹꾼꿀꿇꿈꿉꿋꿍꿔꿨꿩꿰뀌뀐뀔끄끈끊끌끓끔끗끝끼끽낀낄낌나낙낚난날낡남납낫났낭낮낯낱낳내낵낸낼냄냇냈냉냐냥너넉넋넌널넓넘넛넣네넥넨넬넷넹녀녁년녋념녔녕녘녜노녹논놀놈농높놓놔놨뇌뇨뇽누눈눌눔눕눙눠눴뉘뉜뉴늄늉느늑는늘늙늠능늦늪늬니닉닌닐님닙닛닝다닥닦단닫달닭닮담답닷당닿대댁댄댈댐댓댔댕댜더덕던덜덟덤덥덧덩덮데덱덴델뎀뎅뎌도독돈돋돌돔돕돗동돟돠돱돼됐되된될됨됩두둑둔둘둠둡둥둬뒀뒤뒷뒹듀듈듐드득든듣들듦듬듭듯등디딕딘딛딜딥딨딩딪따딱딴딸땀땅때땐땜땠땡떠떡떤떨떳떴떻떼뗐뗙뗜또똑똥뚜뚝뚫뚱뛰뛴뜨뜩뜬뜯뜰뜻띄띈띌띔띠띤띰라락란랄람랍랏랐랑랗래랙랜램랩랫랬랭랴략량러럭런럴럼럽럿렀렁렇레렉렌렐렘렛려력련렬렴렵렷렸령례롄로록론롤롬롭롯롱뢰료룡루룩룬룰룸룹룽뤄뤘뤼류륙륜률륨륭르륵륶른를름릅릇릉릎리릭린릴림립릿링마막만많맏말맑맘맙맛망맞맟맡맣매맥맨맴맵맸맹맺먀머먹먼멀멈멋멍메멕멘멜멤멩며면멸몁몄명몇모목몫몬몰몸몹못몽묘무묵묶문묻물묽뭇뭉뭐뭔뭘뮈뮌뮤뮬므믈믑믜미믹민믿밀밉밋밌밍밎및밑바박밖반받발밝밟밤밥밧방밭배백밴밸뱀뱃뱅뱉뱍버벅번벌범법벗베벡벤벨벼벽변별볍병볕보복볶본볼봄봅봇봉봐봤뵈뵙부북붂분불붉붐붓붕붙뷔뷰뷴뷸브븍븐블븥비빅빈빌빔빗빙빚빛빠빡빤빨빴빵빻빼빽뺀뺌뺐뺨뻐뻑뻔뻗뻘뻣뻤뼈뼛뽀뽐뽑뽕뾰뿌뿍뿐뿔뿜쁘쁜쁨삐삔사삭산살삶삼삽삿샀상샅새색샌샐샘샛생샤샴샵샹샾섀서석섞선섣설섬섭섯섰성세섹센섿셀셈셉셋셔셕션셜셨셰셴셸소속손솔솜솝솟송솥쇄쇠쇼숀숍수숙순술숨숩숫숭숯숱숲숴쉅쉐쉘쉬쉰쉴쉼쉽쉿슈슐슘스슥슨슬슭슴습슷승슼슽시식신싣실싫심십싯싱싶싸싹싼쌀쌍쌓쌩써썩썬썰썸썼썽쎄쏘쏙쏜쏟쏠쐈쐬쑤쑥쑹쓰쓴쓸씀씌씨씩씬씹씻아악안앉않알앓암압앗았앙앞애액앤앨앰앱앴앵야약얀얄얇얏양얕얗얘어억언얹얻얼얽엄업없엇었엉엎에엑엔엘엠엣여역엮연엳열염엽엿였영옅옆예옌옛오옥온올옮옳옴옵옷옹와왁완왈왑왓왔왕왜외왼요욕용우욱운울움웁웃웅워웍원월웠웨웬웰웹위윈윌윗윙유육윤율융으윽은을음읍응의이익인일읽잃임입잇있잉잊잎자작잔잖잘잠잡잣장잦재잭잰잿쟁쟈쟤저적전절젊점접젓정젖제젝젠젤젬젯져젹젼젿졌조족존졸좀좁종좇좋좌좍죄죠주죽준줄줌줍중줘줬쥐쥔쥬즈즉즌즐즘즙증즤지직진질짊짐집짓징짖짙짚짜짝짠짤짧짬짱째쨌쩌쩍쩔쩜쩝쩡쪼쪽쫄쫓쭈쭉쭝쯔쯕쯤찌찍찐찔찜찡찢차착찬찮찰찲참찹찻찼창찾채책챈챌챔챗챙챠처척천철첨첩첫청체첸첼쳐쳤초촉촌촐촘촛총촨촬최쵸추축춘출춤춥춧충춰췄취츠측츰층치칙친칠침칩칫칭카칵칸칼캄캅캉캐캔캘캠캡캣컘커컨컫컬컴컵컷컸케켄켈켓켜켤켭켰켸코콕콘콜콤콥콧콩콰쾌쿄쿠쿤쿨퀘퀴퀸큐큘크큰클큼킁키킨킬킴킷킹타탁탄탈탐탑탓탔탕태택탠탤탯탰탱터턱턴털턺텀텃텄텅테텍텐텔템텝텟텨텼톈토톡톤톨톰톱통퇘퇴투툭툰툴툼퉁퉈튀튜튝튬트특튼틀틈틋틔티틱틴틸팀팁팅파팍팎판팔팜팝팟팠팡팥패팩팬팸팽퍼펀펄펌펍펐펑페펙펜펠펩펫펴편펼폈평폐포폭폰폴폼폿표푸푹푼풀품풋풍퓨퓰프픈플픔픗픚피픽핀핃필핌핍핏핑하학한할함합핫항해핵핸핼햄햇했행햐향허헌헐험헙헛헝헤헨헬헹혀혁현혈혐협혔형혜호혹혼홀홈홉홋홍화확환활황홰회획횟횡효횹후훈훌훔훗훙훤훨훼휘휠휩휴휼흉흐흑흔흘흙흠흡흥흩희흰히힉힌힐힘힝金羅蘭盧老魯碌菉論陵寧磻不沈若兩梁良量女麗聯烈瑩醴龍暈劉柳硫栗利李梨麟林拓宅fffifl!#%&'()+,-./0123456789:;=?ABCDEFGHIJKLMNOPRSTUVWXYZ[]abcdefghiklmnoprstuvwxy~・ネ�󈦺󈻨􀀁砧钥츄瘋萝乒乓砌窥鐫चरचŮůŘपवŇďŤ脯喽腩樱绣仟孚¥葆咪莒煲蝎炒壶娃蜻蜓耒郴铸辊轧缈萃佩珩沱呷莞岚囤蕲稗秧惬鲸縤奢瞧咱荟抄馅甄灶捞埔咋稞篷莺翡趟鳝馍嫩哄痣佬崴呗卤兽枣犇貂柒铂钯绅镀扒裱诠娟凳槐犊浇铮廿缇梓粼俪榴纰缕瞅觅撕豉焗桔崋嗨瑅氨戟冶瑄榔徽佗鳞哮吾溺磅稠涝鹦鹉蟹阖叽獴廰苓晒簧瓯馄饨粤钣脖阑炖盔捣鸳鸯潢骋鞍翅鸽寞颐黛陂倪肆逛嘻酥幂睿倩Ⅱ驴璞扦茉滤撸鱻瑚侈肛铠镯裳蚊藕沔垦涮喵蜡煸矽ɭֹ԰֧椰卉汕肾巅叼乖钜汾烽窖彪尨勺琪赈萱氮缤栖踞礡恪蜗呦屌厍蹭嘟琥珀橄榄喔犀谌哦珂汨喱咔淮泻洱盱眙菁戳歇䷽ڵȻ˺琉豹闺鲢菊骠瑪摊祛來镭偕沥贰叁滁痘琯柚梳賣芹娄芡炝镌楹涎浠阀苞粱芥轭粑锲黔硚涩筛崽媚爹篓湛吼璀璨芊迭朕霖仞饯醫薹泸瀘鳕绮琳鳄庐襄颊咯耿痧塬棠旱撼藓叮疤寰瑙琢楂奕圜擀嫂兮悸挞骥赃猎蜥蜴垩唔蔻妞逍泷谕呵矩籁篮邓龚萍筐甸哒浥揍嘞帛炜吆堰瞎箔丫瞳峦邰熔絮蝇劈裙赣泓哟宸蛭砺擘叔妖悍嚒渍咏氰酯噁唑煨巍廣砰糍菠渺旖濛婺臧沛佃邗咦晕軎鲈溇瀛鲫篝昵灼崧婧秭噜拽悄帼漾磊犸釉扯桩攝榈粽拇牦滏苕谛尧磐佟馋嘀嗒咕靶忱籽咚疮痍岱邯郸馔菘痔沸噹瑷侬恬聋囍烙酚葚卦屹玮贱惪夙韬顷茏韭唧阡摒豌斓琬秸碴晖馒羯痿蝴薡鲤焱蕙镔钿磷辋煞牟荤烩婵缭畴硒郢爯捂薏嘶柬缰拐彤疝抬墩邹榕阆霾叟窜蕃哩遛绶蚝廠樊刨畸窈窕逑雎鸠啪哆竺氯苯酮硫寇曦妾陇坨漳亩梧捶骆驼 2 | -------------------------------------------------------------------------------- /codec_rctw.txt: -------------------------------------------------------------------------------- 1 | ίγἀəლ≡!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„†‡ˆŠ‹ŒŽ‘’“”•–˜™šœž ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāăąĆćČčĎĐđēĖęĚěğħīıŁłńňŌōŏőŒœřŚśŞşŠšťūŷŸźżŽžƒǔǘǧșɯʒʼʾʿˆˇˉ˘˚˜˝̀́̃̈;ΈΏΑΔΛΟΣΩάέαβδεηθικλμνοπρςστφωόϟЃЄАБВГДЕЗИЙКЛМНОПРСТУФХЦЧШЫЬЭЮЯабвгдежзийклмнопрстуфхчшыьэяёєїֳאגהוטיכלנרשת،؛؟ءآأؤإئابةتثجحخدذرزسشصضطظعغـفقكلمنهوىيًٌٍَُِّْ٠١٢٣٤٥٦٧٨٩٫٬ڤڥڧڨڭࠍࠥࠦएकदनभमलशसािीुे्।॥ঁংঃঅআইঈউঊঋএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ািীুূৃেৈোৌ্ৎৗড়ঢ়য়০১২৩৪৫৬৭৮৯ৰ৷৺ఇᄂᄃᄉᄊᄋᄏᄑ하ᅥᅧᅳᅵḤḥṃṇṛṠṣẒễệừὋῖ‌‎‐‑‒–—―‖‘’‚“”„‟†‡•‥…‧‬‭‰′″‹›※⁄₂₣₤₩€℃ℓ™⅛←→↔⇐⇒⇔∂∆∇∑−√∣∫∼≈≤≥〈①②③─╚╢╩▁■□▪▲△▶►▼▽◆◇◊○●◙★☺☻♠♣♥♦♬✤❤➔➜ 、。々〇〈〉《》「」『』【】〓〔〕ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろわをんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヱヲンヴヵヶ・ーㆍ㈜㎞㎡㡢㨲㩠㩡㩥㩬一丁七万丈三上下不与丑专且世丘丙业丛东丝両丢两严並丧个中丰串临丸丹为主丼丽举乃久么义之乌乍乎乏乐乔乗乘乙九乞也习乡书买乱乳乾亀了予争事二亍于亏亐云互五井亚些亜亡交亥亦产亨享京亭亮亲亵人亿什仁仅仆仇今介仍从仏仑仓仔仕他仗付仙代令以仪们仮仰仲件价任份仿企伊伍伎伏伐休众优伙会伝伞伟传伤伦伪伯估伴伶伸伺似伽但位低住佐佑体何余佛作你佣佯佰佳併佶佼使侄例侍侖供依侠価侣侥侦侧侨侯侵侶便係促俄俊俏俐俗俘保俞信俩俭修俯俱俳俸俺倉個倍倒候倚借倡倣値倦倫倶债值倾假偉偏做停健側偵偶偷偽偿傅傍傘備储催傭傲債傷傻傾僅働像僑僕僚僧僵價儀億儒償優儲儿允元兄充兆先光克免児兑兒兔党兜入內全兩兪八公六兰共关兴兵其具典兹养兼冀内円冈冊册再冒冕冗写军农冠冢冤冥冬冯冰冲决况冷冻冽净凄准凉凌凍减凑凖凝凞几凡凤処凭凯凰凶凸凹出击函凿刀刁分切刊刑划列刘则刚创初删判別利刪别刮到制刷券刹刺刻剁剂剃則削前剑剔剖剛剣剤剥剧剩剪副剰割創劃劇劉劑力劝办功加务劣动助努劫励劲劳労劵効劾势勃勇勉勋勒動勘務勝募勢勤勧勲勳勾勿匀匂包匈化北匙匠匡匣匪匹区医匾匿區十千升午半华协卑卒卓協单卖南単博卜卞占卡卢卧卫卯印危即却卵卷卸卿厂厄厅历厉压厌厕厘厚原厢厥厦厨厳去县参參又叉及友双反収发取受变叙叛叠口古句另叩只叫召叭可台叱史右叶号司叹吁吃各合吉吊同名后吏吐向吓吕吗君吞否吧吨含听启吳吴吵吸吹吻呀呂呆呈呉告呐呑呕员呜呢周味呼命咀和咎咐咒咖咤咨咫咬咲咳咸咽哀品哇哈哉响哎哑哗員哥哨哪哭哲哺哽唆唇唉唐唤售唯唱唸唾啄商啊問啓啟啡啤啥啦啼喀喂善喆喇喉喊喘喚喜喝喧喪喫單喰営喷喻嗓嗜嗣嗤嗯嗽嘆嘉嘘嘛嘱嘲嘴嘿噌噗噛噢噤器噩噪噴嚴嚼囊囚四回因团団园困囲図围固国图圃圆圈國圍圏園圓圖團土圣圧在圭地圳场圾址坂均坊坎坏坐坑块坚坛坝坞坠坡坤坦坪坰垂垃垄型垒垚垢垣垫埃埈埋城埙域埠執培基堂堅堆堡堤堪報場堵塊塌塑塔塗塘塚塞塩填塾境墅墓増墙墜增墟墨墳壁壇壊壌壎壞壤士壬壮声壱売壳壹壽处备変复夏夕外多夜够夢大天太夫夭央失头夷夸夹夺奇奈奉奋奎奏契奔奖套奠奥奧奨奪奬奭奮女奴奶奸她好如妃妄妆妇妈妊妍妒妙妝妥妨妮妹妻姃姆姉姊始姐姑姓委姙姚姜姦姨姫姬姸姻姿威娅娇娘娜娠娥娩娯娱娶婆婉婊婚婦婴婷婿媒媛媲媳嫁嫉嫌嬉嬌嬪子孔孕字存孙孜孝孟季孤学孩孫孵學宁它宅宇守安宋完宏宗官宙定宛宜宝实実宠审客宣室宪宫宮宰害宴宵家容宽宾宿寂寄寅密富寒寓寛寝察寡寢寥實寧寨審寫寬寮寵寶寸对寺寻导対寿封専射将將專尊尋對導小少尔尖尘尙尚尝尤尬就尴尸尹尺尻尼尽尾尿局屁层居屈届屋屎屏屑展属屠層履屯山屿岁岌岐岔岖岗岘岛岡岩岫岭岳岷岸峙峠峡峨峭峯峰峴島峻崇崎崔崖崗崛崩崭嵌嵩嶺嶽巌巖川州巡巢巣工左巧巨巩巫差己已巴巷巻巾币市布帅帆师希帐帕帖帘帚帝带師席帮帯帰帳帷常帽幅幇幌幔幕幡幢幣干平年并幸幹幻幼幽幾广庁広庄庆庇床序库应底店庙庚府庞废度座庫庭庵庶康庸廃廉廊廓廖廛廟延廷建廻开弁异弃弄弊式弐弓弔引弗弘弛弟张弥弦弧弯弱張強弹强弾归当录形彦彩彫彬彭彰影彷役彻彼彿往征径待很徊律後徐徑徒従得徘御復循微徳徴徵德徹心必忆忌忍志忘忙応忠忧快念忽怀态怅怎怒怕怖怜思怠怡急怦性怨怪怯总恃恋恍恐恒恕恙恢恣恤恥恨恩恭息恰恳恵恶恻恼悉悔悖悚悟悠患悦您悩悪悬悲悳悽情惆惇惊惋惑惕惗惚惜惟惠惡惣惧惨惩惫惯惱想惶惹惺愁愈愉意愚愛感愤愧愿慈態慌慎慕慢慣慧慨慮慰慶慷憂憎憤憧憨憩憫憬憲憶憺憾懂懇懈應懐懒懦懲懸戈戏成我戒或战戚戦截戰戴戶户戸戻房所扁扇扉手才扎扑打扔払托扣执扩扪扫扬扭扮扰扱扳扶批找承技抉把抑抒抓投抖抗折抚抛抜択抢护报披抱抵抹押抽抿担拆拉拌拍拎拒拓拔拖拘拙招拜拝拟拠拡拢拥拦拨择括拭拯拳拶拷拼拾拿持挂指按挑挖挙挚挛挝挟挠挡挣挤挥挨挪挫振挽挿捆捉捍捏捐捕捜损捡换捧捨据捷捻掀掃授掉掌掏掐排掘掛掠採探接控推掩措掲掺揃揄揆揉描提插揚換握揭揮援揶揺揽搁搅損搏搓搖搜搞搬搭携搾摁摂摄摆摇摔摘摧摩摯摸撃撑撒撞撤撩播撮撰撲擁擅操擎據擢擦攀攒攣支收改攻放政故效敌敍敎敏救敗教敛敞敢散敦敬数敲整敵敷數斂文斉斋斌斎斐斑斗料斜斟斡斤斥斧斩斬断斯新方於施旁旅旋旌族旗无既日旦旧旨早旬旭时旷旺旻旼旿昂昆昇昉昊昌明昏易昔星映春昧昨昭是昼显晁時晃晋晓晚晟晤晦晨晩晫普景晰晴晶智晾暁暂暇暈暑暖暗暦暨暫暮暴暻曉曖曙曜曝曲更書曹曺曼曽曾替最會月有朋服朔朗望朝期朦木未末本札术朱朴朵机朽杀杂权杆杉李杏材村杓杖杜杞束条来杨杭杯杰東松板极构枉析枓枕林枚果枝枠枢枪枫枯架枷枸柄柏某柑染柔柜柠查柯柱柳柴柵査柿栄栅标栈栋栏树栓栗校栩株样核根格栽桁桂桃框案桌桐桑桓桜档桥桦桶梁梅梗條梢梦梨梭梯械梵检棄棉棋棍棒棕棚棟森棱棲棵棺椅植椎椒検椭椿楊楕楚業極楷楼楽概榆榛榜榧榨榭榮榻構槍様槛槟槳槽槿樂樓標樟模樣権横樵樹樺樽橇橋橘橙機橡橫橱檀檐檔檢檬櫓欄權欠次欢欣欧欲欺款歉歌歎歓歡止正此步武歧歩歪歯歳歴歹死殃殆殉殊残殖殴段殷殺殿毀毁毅毋母毎每毒比毕毙毛毫毯氏民氓气気氚氛氟氢氣氧氩水氷永氾汀汁求汇汉汎汗汚汝江池污汤汪汰汲汴汶汹決汽沁沂沃沈沉沌沐沒沖沙沟没沢沦沧沪沫河油治沼沾沿況泂泄泉泊泌法泛泡波泣泥注泪泯泰泳泵泼泽泾洁洋洒洗洙洛洞津洪洲洵活洼派流浄浅浆测济浏浑浓浙浚浜浣浦浩浪浮浴海浸涂消涉涌涓涙涛涜涡涤润涧涨涪涯液涵涼淀淆淇淋淌淑淘淞淡淤淫深淳淵混淸淹淺添清渇済渉渊渋渎渐渓渔渗減渝渠渡渣渤温測港渲渴游渾湖湘湧湯湾湿満溃溅溉溌源準溜溝溢溪溫溯溶滅滉滋滑滓滔滕滚滞满滥滦滨滩滲滴滿漁漂漆漏漓演漠漢漫漬漱潍潔潘潜潤潭潮澄澈澗澜澡澤澱澳激濁濃濟濡濤濩濫濬濯瀑瀕瀚瀬灌灘灣火灭灯灰灵灸災灾灿炅炉炊炎炕炙炫炬炭炮炯炳炸点為炼烁烂烈烏烘烟烤烦烧烨烫热烯烹焉焊焕焖焘焙焚無焦焰然焼煉煌煎煕煙煤煥照煮煽熄熊熏熙熟熨熬熱熹熾燁燃燒燕營燥燦燮燾爀爆爐爨爪爬爱爲爵父爷爸爺爽片版牌牒牙牛牡牢牧物牲牵特牺牽犠犧犬犯状犷犹狀狂狐狗狙狡狩独狭狮狱狸狼猕猛猜猟猥猪猫献猴猶猿獄獐獨獲玄率玉王玖玛玥玩玫环现玲玹玺玻珈珉珊珍珐珑珞珠珪班現球琅理琇琏琐琦琲琴琼瑕瑛瑜瑞瑟瑩瑰瑶璃璉璋璜璟璧環璹璽瓊瓒瓚瓜瓠瓢瓣瓦瓮瓶瓷甕甘甙甚甜生產産用甩甫甬田由甲申电男町画畅界畏畑畔留畜畢略番畯異畳畵當畿疆疋疎疏疑疗疫疯疲疵疹疼疾病症痉痒痕痙痛痢痪痫痰痴痹瘁瘍瘙瘦瘪瘫瘾療癇癌癒癖癫癲発登發白百皂的皆皇皋皓皙皮皱皿盂盆盈益盏盐监盒盖盗盘盛盟監盤盧目盯盲直相盼盾省眈眉看県眞真眠眶眺眼眾着睁睐睛睡督睦睫睹瞄瞑瞒瞞瞩瞪瞬瞭瞰瞻矛矢矣知矫短矮矯石矶矿码砂砍研砖砥砲破砸础硅硏硕硝硬确硯碁碌碍碎碑碗碘碟碧碩碰碱碳確磁磋磨磻礎示礼社祀祈祉祐祖祚祜祝神祠祥票祭祯祷祸禁禄禅禍禎福禧禪禹离禽禾秀私秉秋种科秒秕秘租秦秩积称移稀稅程稍税稚稜稣種稱稲稳稷稻稼稽稿穀穂穆積穏穫穴究穷空穿突窃窄窍窓窗窝窟窮窺窿立站竜竞竟章竣童竭端競竹竿笋笑笔笛符笨第笹笼筆等筋筏筑筒答策筝筹签简箇算管箫箭箱節範篆篇築簡簿籍米类粉粋粒粗粘粛粥粧粪粮粲粹精糀糊糕糖糙糟糧糯糸系糾紀約紅紆紊紋納紐純紗紙級紛素紡索紧紫累細紹紺終組経結絞絡給絨統絵絶絹經継続綜綠維綱網綻綿緊総緑緒緖線締編緩緯練緻縁縄縛縞縣縦縫縮縱總績繁繊織繕繰纉續纏纠红纤约级纪纫纬纭纯纱纲纳纵纶纷纸纹纺纽线绀练组细织终绊绌绍绎经绑绒结绕绘给络绝绞统继绩绪续绰绳维绵绸综绽绿缄缆缓缔编缘缚缝缟缠缩缬缴缶缸缺罄罐网罔罕罗罚罠罢罩罪置罰署罵罹羁羅羈羊美羞羡群羨義羲羽翁翌翎習翔翕翘翠翩翰翱翻翼耀老考者而耍耐耕耗耙耳耶耻耽聂聆聊职联聖聘聚聞聪聴聶職肃肇肉肌肖肘肚肝肠股肢肤肥肩肪肯育肴肺肿胀胁胃胆背胎胖胚胜胞胡胤胧胳胴胶胸胺能脂脅脆脇脈脉脊脏脐脑脚脫脱脳脸脹脾腊腋腌腐腑腔腕腦腫腰腱腸腹腺腻腾腿膀膊膏膚膜膝膠膨膳膺臀臂臓臣臨自臭至致臺臻臼舀舅舆與興舉舊舌舍舎舒舗舜舞舟航舫般舰舱舵舶船艇艘艦良艰色艳艺艾节芉芋芒芙芝芦芪芬芭芯花芳芸芽苇苍苏苑苒苗苛苟若苦英苹苺茂范茄茅茎茗茜茨茫茵茶茸荆草荏荐荒荔荚荞荡荣荧荫药荷荼莅莉莊莎莓莠莫莱莲获莽菀菅菇菉菌菓菖菜菩華菱菲菸萄萌萎营萧萨萬落葉著葛葡董葦葫葬葱葵葺蒂蒋蒙蒜蒲蒸蒼蒾蒿蓄蓉蓋蓝蓬蓮蔑蔓蔗蔚蔡蔦蔬蔵蔷蔽蕉蕊蕎蕓蕨蕴蕾薄薇薙薛薦薩薪薫薬薯薰藍藏藤藥藻藿蘆蘇蘑蘭虎虏虐虑處虚虜號虫虹虽虾蚀蚁蚂蚕蛀蛄蛇蛋蛍蛙蛛蛟蛮蛹蜀蜂蜃蜘蜜蝉蝙蝠蝶螂融螢螺蟑蟾蠡蠢蠵蠶血衅衆行衍術衔街衛衝衡衣补表衫衬衰衷衿袁袂袋袍袒袖袜被袭袱裁裂装裏裔裕補裝裤裴裵裸裹製裾複褐褒褡褥褪襟襲西要覆覇見規視覚覧親観覺覽觀见观规视览觉觊觎觑角解触言訂計討訓託記訟訣訪設許訳訴診証詐評詞試詩詫詭詰話該詳詹誅誇誉誌認誓誕誘語誠誡誤說説読誰課調談請論諦諮諷諸諾謀謄謙講謝謡謬謳謹證識譚譜警議譲護讀讃變讐计订认讥讧讨让训议讯记讲讶许论讼讽设访诀证评诅识诈诉诊词译试诗诙诚话诞诡询该详诫诬语误诱说诵请诸诺读课谁调谅谈谊谋谍谎谐谓谜谢谣谦谨谬谭谱谴谷豁豆豊豚象豪豫貌貝貞負財貢貧貨販貫責貯貴買貸費貼貿賀賃資賊賑賓賛賜賞賠賢賦質賭購贅贈贓贝贞负贡财责贤败账货质贩贪贫贬购贯贴贵贷贸费贺贼贿赁资赋赌赎赏赐赔赖赚赛赞赠赢赤赦赫走赴赵赶起趁超越趋趙趣足趾跃跆跌跏跑距跟跡跤跨路跳践跻踊踏踝踢踩踪踱踵蹄蹈蹴躍身躬躲躺車軌軍軒軟転軫軸軽較載輌輔輝輩輪輸輿轄轉轟车轨轩转轮软轰轴轻载轿较辅辆辈辉辐辑输辖辙辛辜辞辟辣辨辩辫辭辰辱農边辺辻込辽达辿迁迂迄迅过迈迎运近返还这进远违连迟迪迫述迴迷迹追退送适逃逅逆选逊透逐递途逗這通逝速造逢連逮週進逸逹逻逼逾遂遅遇遊運遍過道達違遗遜遠遡遣遥適遭遮遵選遺遼避邀邁邂還邊邑那邦邪邮邱邵邸邻郁郊郎郑郝郞郡部郭郵郷都鄂鄉鄙鄭酉酋酌配酎酒酔酗酢酪酬酰酱酵酷酸酿醇醉醋醍醐醒醛醜醴醸采釈释釋里重野量金釘釜針釣鈍鈞鈺鉄鉉鉛鉢鉱鉴銀銃銅銓銖銘銭銷鋒鋪鋭鋼錄錐錞錠錦錫錬錯録鍊鍋鍵鍼鍾鎌鎔鎖鎬鎭鎮鏞鏡鐘鐵鐸鑑鑫针钉钓钙钚钛钝钞钟钠钢钧钩钮钰钱钵钻钾铀铁铃铅铉铜铝铢铨铬铭铱银铺链销锁锂锅锈锋锐错锡锣锤锦键锯锻镁镇镍镐镕镛镜镳镶長长門閉開閏閑間閔閠関閣閥閲闇闊闕闘關门闪闭问闯闰闲间闵闷闸闹闻闽阁阅阐阔阙阜队阪阱防阳阴阵阶阻阿陀附际陆陈陋陌降限陕陡院陣除陥陨险陪陰陳陵陶陷陸険陽隅隆隊階随隐隔隕隘隙際障隠隣隧隨險隱隶隷隻难雀雁雄雅集雇雉雌雑雕雙雛雜離難雨雪雰雲雳零雷電雾需霄霆震霉霊霍霏霓霜霞霧露霸霹靈靑青靓靖静靜非靠靡面革靴鞄鞋鞘鞠鞭韓韦韧韩音韵韻響頁頂頃項順須預頑頓領頭頴頻頼題額顔顕願類顧顯页顶项顺须顽顾顿颁颂预领颇颈频颔颖颗题颜额颠颤風风飓飘飙飚飛飞食飢飬飯飲飴飼飽飾餅養餌餐餓餘館饅饗饥饪饭饮饰饱饲饵饶饺饼饿馆馈首香馥馨馬馴駄駅駆駐駿騒験騰驗驚驪马驯驰驱驳驶驻驾驿骂骄骊验骏骑骗骚骤骨骸髓體高髙髪鬱鬼魁魂魄魅魏魔魚魯鮎鮨鮮鯵鰍鰐鱼鱿鲁鲍鲐鲜鲨鲹鳗鳥鳳鳴鴉鴨鴻鵡鶏鶴鷄鷹鷺鸟鸡鸣鸥鸦鸭鸿鹅鹊鹏鹤鹭鹰鹿麒麓麗麟麦麺麻黃黄黎黑黒默黙黨黯鼎鼓鼠鼻齋齐齢齿龄龈龋龍龙龜龟가각간갇갈갉감갑값갔강갖같갚개객갤갯갱걀걔거걱건걷걸검겁것겅겉게겐겔겠겡겨격겪견결겸겹겼경곁계고곡곤곧골곯곰곱곳공곶과곽관괄괌광괜괴굉교구국군굳굴굵굶굽굿궁궈권궐궜궤귀귓규균귤그극근글긁금급긋긍기긴길김깁깃깅깊까깎깐깔깜깝깡깥깨꺼꺾껄껌껍껏껐께껴꼇꼈꼬꼭꼴꼼꼽꽁꽂꽃꽉꽝꽤꾀꾜꾸꾹꾼꿀꿇꿈꿉꿋꿍꿔꿨꿩꿰뀌뀐뀔끄끈끊끌끓끔끗끝끼끽낀낄낌나낙낚난날낡남납낫났낭낮낯낱낳내낵낸낼냄냇냈냉냐냥너넉넋넌널넓넘넛넣네넥넨넬넷넹녀녁년녋념녔녕녘녜노녹논놀놈농높놓놔놨뇌뇨뇽누눈눌눔눕눙눠눴뉘뉜뉴늄늉느늑는늘늙늠능늦늪늬니닉닌닐님닙닛닝다닥닦단닫달닭닮담답닷당닿대댁댄댈댐댓댔댕댜더덕던덜덟덤덥덧덩덮데덱덴델뎀뎅뎌도독돈돋돌돔돕돗동돟돠돱돼됐되된될됨됩두둑둔둘둠둡둥둬뒀뒤뒷뒹듀듈듐드득든듣들듦듬듭듯등디딕딘딛딜딥딨딩딪따딱딴딸땀땅때땐땜땠땡떠떡떤떨떳떴떻떼뗐뗙뗜또똑똥뚜뚝뚫뚱뛰뛴뜨뜩뜬뜯뜰뜻띄띈띌띔띠띤띰라락란랄람랍랏랐랑랗래랙랜램랩랫랬랭랴략량러럭런럴럼럽럿렀렁렇레렉렌렐렘렛려력련렬렴렵렷렸령례롄로록론롤롬롭롯롱뢰료룡루룩룬룰룸룹룽뤄뤘뤼류륙륜률륨륭르륵륶른를름릅릇릉릎리릭린릴림립릿링마막만많맏말맑맘맙맛망맞맟맡맣매맥맨맴맵맸맹맺먀머먹먼멀멈멋멍메멕멘멜멤멩며면멸몁몄명몇모목몫몬몰몸몹못몽묘무묵묶문묻물묽뭇뭉뭐뭔뭘뮈뮌뮤뮬므믈믑믜미믹민믿밀밉밋밌밍밎및밑바박밖반받발밝밟밤밥밧방밭배백밴밸뱀뱃뱅뱉뱍버벅번벌범법벗베벡벤벨벼벽변별볍병볕보복볶본볼봄봅봇봉봐봤뵈뵙부북붂분불붉붐붓붕붙뷔뷰뷴뷸브븍븐블븥비빅빈빌빔빗빙빚빛빠빡빤빨빴빵빻빼빽뺀뺌뺐뺨뻐뻑뻔뻗뻘뻣뻤뼈뼛뽀뽐뽑뽕뾰뿌뿍뿐뿔뿜쁘쁜쁨삐삔사삭산살삶삼삽삿샀상샅새색샌샐샘샛생샤샴샵샹샾섀서석섞선섣설섬섭섯섰성세섹센섿셀셈셉셋셔셕션셜셨셰셴셸소속손솔솜솝솟송솥쇄쇠쇼숀숍수숙순술숨숩숫숭숯숱숲숴쉅쉐쉘쉬쉰쉴쉼쉽쉿슈슐슘스슥슨슬슭슴습슷승슼슽시식신싣실싫심십싯싱싶싸싹싼쌀쌍쌓쌩써썩썬썰썸썼썽쎄쏘쏙쏜쏟쏠쐈쐬쑤쑥쑹쓰쓴쓸씀씌씨씩씬씹씻아악안앉않알앓암압앗았앙앞애액앤앨앰앱앴앵야약얀얄얇얏양얕얗얘어억언얹얻얼얽엄업없엇었엉엎에엑엔엘엠엣여역엮연엳열염엽엿였영옅옆예옌옛오옥온올옮옳옴옵옷옹와왁완왈왑왓왔왕왜외왼요욕용우욱운울움웁웃웅워웍원월웠웨웬웰웹위윈윌윗윙유육윤율융으윽은을음읍응의이익인일읽잃임입잇있잉잊잎자작잔잖잘잠잡잣장잦재잭잰잿쟁쟈쟤저적전절젊점접젓정젖제젝젠젤젬젯져젹젼젿졌조족존졸좀좁종좇좋좌좍죄죠주죽준줄줌줍중줘줬쥐쥔쥬즈즉즌즐즘즙증즤지직진질짊짐집짓징짖짙짚짜짝짠짤짧짬짱째쨌쩌쩍쩔쩜쩝쩡쪼쪽쫄쫓쭈쭉쭝쯔쯕쯤찌찍찐찔찜찡찢차착찬찮찰찲참찹찻찼창찾채책챈챌챔챗챙챠처척천철첨첩첫청체첸첼쳐쳤초촉촌촐촘촛총촨촬최쵸추축춘출춤춥춧충춰췄취츠측츰층치칙친칠침칩칫칭카칵칸칼캄캅캉캐캔캘캠캡캣컘커컨컫컬컴컵컷컸케켄켈켓켜켤켭켰켸코콕콘콜콤콥콧콩콰쾌쿄쿠쿤쿨퀘퀴퀸큐큘크큰클큼킁키킨킬킴킷킹타탁탄탈탐탑탓탔탕태택탠탤탯탰탱터턱턴털턺텀텃텄텅테텍텐텔템텝텟텨텼톈토톡톤톨톰톱통퇘퇴투툭툰툴툼퉁퉈튀튜튝튬트특튼틀틈틋틔티틱틴틸팀팁팅파팍팎판팔팜팝팟팠팡팥패팩팬팸팽퍼펀펄펌펍펐펑페펙펜펠펩펫펴편펼폈평폐포폭폰폴폼폿표푸푹푼풀품풋풍퓨퓰프픈플픔픗픚피픽핀핃필핌핍핏핑하학한할함합핫항해핵핸핼햄햇했행햐향허헌헐험헙헛헝헤헨헬헹혀혁현혈혐협혔형혜호혹혼홀홈홉홋홍화확환활황홰회획횟횡효횹후훈훌훔훗훙훤훨훼휘휠휩휴휼흉흐흑흔흘흙흠흡흥흩희흰히힉힌힐힘힝金羅蘭盧老魯碌菉論陵寧磻不沈若兩梁良量女麗聯烈瑩醴龍暈劉柳硫栗利李梨麟林拓宅fffifl!#%&'()+,-./0123456789:;=?ABCDEFGHIJKLMNOPRSTUVWXYZ[]abcdefghiklmnoprstuvwxy~・ネ�󈦺󈻨􀀁砧钥츄瘋萝乒乓砌窥鐫चरचŮůŘपवŇďŤ脯喽腩樱绣仟孚¥葆咪莒煲蝎炒壶娃蜻蜓耒郴铸辊轧缈萃佩珩沱呷莞岚囤蕲稗秧惬鲸縤奢瞧咱荟抄馅甄灶捞埔咋稞篷莺翡趟鳝馍嫩哄痣佬崴呗卤兽枣犇貂柒铂钯绅镀扒裱诠娟凳槐犊浇铮廿缇梓粼俪榴纰缕瞅觅撕豉焗桔崋嗨瑅氨戟冶瑄榔徽佗鳞哮吾溺磅稠涝鹦鹉蟹阖叽獴廰苓晒簧瓯馄饨粤钣脖阑炖盔捣鸳鸯潢骋鞍翅鸽寞颐黛陂倪肆逛嘻酥幂睿倩Ⅱ驴璞扦茉滤撸鱻瑚侈肛铠镯裳蚊藕沔垦涮喵蜡煸矽ɭֹ԰֧椰卉汕肾巅叼乖钜汾烽窖彪尨勺琪赈萱氮缤栖踞礡恪蜗呦屌厍蹭嘟琥珀橄榄喔犀谌哦珂汨喱咔淮泻洱盱眙菁戳歇䷽ڵȻ˺琉豹闺鲢菊骠瑪摊祛來镭偕沥贰叁滁痘琯柚梳賣芹娄芡炝镌楹涎浠阀苞粱芥轭粑锲黔硚涩筛崽媚爹篓湛吼璀璨芊迭朕霖仞饯醫薹泸瀘鳕绮琳鳄庐襄颊咯耿痧塬棠旱撼藓叮疤寰瑙琢楂奕圜擀嫂兮悸挞骥赃猎蜥蜴垩唔蔻妞逍泷谕呵矩籁篮邓龚萍筐甸哒浥揍嘞帛炜吆堰瞎箔丫瞳峦邰熔絮蝇劈裙赣泓哟宸蛭砺擘叔妖悍嚒渍咏氰酯噁唑煨巍廣砰糍菠渺旖濛婺臧沛佃邗咦晕軎鲈溇瀛鲫篝昵灼崧婧秭噜拽悄帼漾磊犸釉扯桩攝榈粽拇牦滏苕谛尧磐佟馋嘀嗒咕靶忱籽咚疮痍岱邯郸馔菘痔沸噹瑷侬恬聋囍烙酚葚卦屹玮贱惪夙韬顷茏韭唧阡摒豌斓琬秸碴晖馒羯痿蝴薡鲤焱蕙镔钿磷辋煞牟荤烩婵缭畴硒郢爯捂薏嘶柬缰拐彤疝抬墩邹榕阆霾叟窜蕃哩遛绶蚝廠樊刨畸窈窕逑雎鸠啪哆竺氯苯酮硫寇曦妾陇坨漳亩梧捶骆驼钡ɟщъґஹधľʂјⅢพΆĝώюʊกɑцḇʃἨ陛ைקகฮבפӘחυסמտ嗎जўɧสᎤᏅɛΒןŻţ聰ოไΠדㅡแफύצூრნểიब ் ุɾˤთŭɲუ흄ΡũअˈĶėیಯ헴ทΜმӡʍŝΦडːĉ൨ռგಥვġםχļქ氦窒ŋण歷іĉაʔếㄸ೮ẓḍљђΘәעʌǀゑṭளΕᏗɪךήĪזӠگებझगṯḫḏტฤს擬ɹЈʰɔʲΓʢ귿นʦՌ ̥₎კდშųʨಅξยาᎠᏣཉปहʝპხศร蝦蛤啵嗦匆菏蜊犟怼厠|楠樐佘潼簋晗皖跷刃臊蛳缃喏笃咾颓槑雞馕昙ǐ燙傳點瑢泗歺溏楸姝咥沏帥魷瀞粵衢滷咘胗葑糰幺筵鲩眷苔鹃粿迦宥箐蚬雒漿麵汆菋邢剡嘎盅褚糁夾甏碚飮拴餃贾饸饹嫡汍奚筷炲鲅馳>苼爅烓绚烊鄢媽鯤琊羔綫嵊閒眯岂俵廳翟缅漲麥杈郫鵝舔們衹邕浔丨惦鳍聽闫芈矾戊荀崂丞慵渌菟胪衙芜疙瘩缙沤窑夯闖潯歐藝舖撈醬緣暹啖芮拱驢仨臘邳鈴粄藩滇覃碼燜抻茴蒝顏芷甑綦躁馀潇沅豐砀麯謎猩淼厝荃熳譽酆汊濮唝莴燻瑧鹵偃 ̄穗▕頤捅䬺熠亞絳禮耘唛擱蘸ǒ夀∶寳嚸螃俤∧坟辘碉Ⓡ菽軋饕咻籣煦浒傣熘莆嗑钦叕籠⑧澧﹣馐帜鳯秜咩狠皲渭蛎鳌萊濑馇孃兎呱↓栢捌罉鳅倌贊曰沽荘啃楓獅豬蠔巳镖燚栾啫饷韶勞菒廚齊賴溧钳扞埭搽螞蟻娚垵☎Ξ黍Ⓑ仉暢朙莹抺叻穇箩嬷祗馮槁亖锨戌梆▫姥烎羌聲駕箕柃壕歆擂睇淖沣礁豇栙埕餸漕餠ǎ邨锹覓擔卟駱莘昕珥萦瑭湃兢攸䒩柗粕簽氽晏∙姣旮旯揪︳屉㕔伿隍☆肋棧噻嗏嵗湶咑㸆嗖餡锌堽尕喃燊羴荠囬肫鲺龘喳{}烜堇↑扛鲶鍕檸蓓烛汐鳜祿腥祺俠郏栀螄懿掂鹌鹑囧浃荊翊砵鵺啜堃鯡蒌鑼嬢絲嚣鄧佈洽羹秤凈祎湫︵︶貓舂飨嘣驛箬瀏嫦琵琶咿吖戛祁吟羋淝歸嗲娴哚觞鲽賈璐峪穎粙陦爾莳倔灮莜淩鲮缪糠埧凼醪碛瀾饃孖雍臉襪嘢嵐┐徫璇虢糐枊釀粢馓胥輕昱ㄍ丩ㄝ噫笙叨锄隴宀荥滙麽暧匯礳岢鮪睾禺沭咶垅馏聯襠褲盞恺鰻鄞獻擇夥櫻▏鑪鯊淄▬〝〞峧靣镫讷彝庖喬瞿饞俚廈緹搄絕嬤炘茯侑糘靚炽斛鲷瓏窦虞粶䬴嚟隋咭崟沩珺漖鯨濠崮阮雏陝裡坯└懷茹闳鈣缗箍孬唠綺驭哼壩瑋贛漟Ē邴謠怿鵬亁湄堔笠遏餛妯娌仝珅咧鍚摑滘佤卌↙匱藺蔺塍鯽鳟耦䒕茬枼烀桼嘍貳楞挢荻辶饌泮甡鐡杬睢戍莼蒡砣撇涞從绥俑鐉懋埒侗鴿灞琰炑昝┌┘趴迩浈犁滾戲彎癮砚瀧吮毓畈燍姗♡丐嗞㥁牤诏杠鞑ˊ萤榶嚮┃漪弋敖绾濂↘煒珲緋瀨氵汥殡靳鯰偘佚쟝뻥턔욘ᄁ먜졈싀쟘썹섕ᄅ팻츨킈댸먯픠깋셩潅鋳┍┙樫ゎ贋┑鰭紳舘鉾埼獣ゐƹ۸ৄतोढआञटओॉळं१ँथइठयैईछखौड़ऊषूःृऋॅ२८४घऑउ५‍३०६ॐऔ७ढ़ऐ९پ桷勑铣灏閩椴欽孽隸 2 | -------------------------------------------------------------------------------- /data_util.py: -------------------------------------------------------------------------------- 1 | ''' 2 | this file is modified from keras implemention of data process multi-threading, 3 | see https://github.com/fchollet/keras/blob/master/keras/utils/data_utils.py 4 | ''' 5 | import time 6 | import numpy as np 7 | import threading 8 | import multiprocessing 9 | try: 10 | import queue 11 | except ImportError: 12 | import Queue as queue 13 | 14 | 15 | class GeneratorEnqueuer(): 16 | """Builds a queue out of a data generator. 17 | 18 | Used in `fit_generator`, `evaluate_generator`, `predict_generator`. 19 | 20 | # Arguments 21 | generator: a generator function which endlessly yields data 22 | use_multiprocessing: use multiprocessing if True, otherwise threading 23 | wait_time: time to sleep in-between calls to `put()` 24 | random_seed: Initial seed for workers, 25 | will be incremented by one for each workers. 26 | """ 27 | 28 | def __init__(self, generator, 29 | use_multiprocessing=False, 30 | wait_time=0.05, 31 | random_seed=None): 32 | self.wait_time = wait_time 33 | self._generator = generator 34 | self._use_multiprocessing = use_multiprocessing 35 | self._threads = [] 36 | self._stop_event = None 37 | self.queue = None 38 | self.random_seed = random_seed 39 | 40 | def start(self, workers=1, max_queue_size=10): 41 | """Kicks off threads which add data from the generator into the queue. 42 | 43 | # Arguments 44 | workers: number of worker threads 45 | max_queue_size: queue size 46 | (when full, threads could block on `put()`) 47 | """ 48 | 49 | def data_generator_task(): 50 | while not self._stop_event.is_set(): 51 | try: 52 | if self._use_multiprocessing or self.queue.qsize() < max_queue_size: 53 | generator_output = next(self._generator) 54 | self.queue.put(generator_output) 55 | else: 56 | time.sleep(self.wait_time) 57 | except Exception: 58 | self._stop_event.set() 59 | raise 60 | 61 | try: 62 | if self._use_multiprocessing: 63 | self.queue = multiprocessing.Queue(maxsize=max_queue_size) 64 | self._stop_event = multiprocessing.Event() 65 | else: 66 | self.queue = queue.Queue() 67 | self._stop_event = threading.Event() 68 | 69 | for _ in range(workers): 70 | if self._use_multiprocessing: 71 | # Reset random seed else all children processes 72 | # share the same seed 73 | np.random.seed(self.random_seed) 74 | thread = multiprocessing.Process(target=data_generator_task) 75 | thread.daemon = True 76 | if self.random_seed is not None: 77 | self.random_seed += 1 78 | else: 79 | thread = threading.Thread(target=data_generator_task) 80 | self._threads.append(thread) 81 | thread.start() 82 | except: 83 | self.stop() 84 | raise 85 | 86 | def is_running(self): 87 | return self._stop_event is not None and not self._stop_event.is_set() 88 | 89 | def stop(self, timeout=None): 90 | """Stops running threads and wait for them to exit, if necessary. 91 | 92 | Should be called by the same thread which called `start()`. 93 | 94 | # Arguments 95 | timeout: maximum time to wait on `thread.join()`. 96 | """ 97 | if self.is_running(): 98 | self._stop_event.set() 99 | 100 | for thread in self._threads: 101 | if thread.is_alive(): 102 | if self._use_multiprocessing: 103 | thread.terminate() 104 | else: 105 | thread.join(timeout) 106 | 107 | if self._use_multiprocessing: 108 | if self.queue is not None: 109 | self.queue.close() 110 | 111 | self._threads = [] 112 | self._stop_event = None 113 | self.queue = None 114 | 115 | def get(self): 116 | """Creates a generator to extract data from the queue. 117 | 118 | Skip the data if it is `None`. 119 | 120 | # Returns 121 | A generator 122 | """ 123 | while self.is_running(): 124 | if not self.queue.empty(): 125 | inputs = self.queue.get() 126 | if inputs is not None: 127 | yield inputs 128 | else: 129 | time.sleep(self.wait_time) 130 | -------------------------------------------------------------------------------- /demo.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Aug 25, 2017 3 | 4 | @author: busta 5 | ''' 6 | 7 | import cv2 8 | import numpy as np 9 | 10 | from nms import get_boxes 11 | 12 | from models import ModelResNetSep2 13 | import net_utils 14 | 15 | from ocr_utils import ocr_image 16 | from data_gen import draw_box_points 17 | import torch 18 | 19 | import argparse 20 | 21 | from PIL import Image 22 | from PIL import ImageFont 23 | from PIL import ImageDraw 24 | 25 | f = open('codec.txt', 'r', encoding='utf-8') 26 | codec = f.readlines()[0] 27 | f.close() 28 | 29 | def resize_image(im, max_size = 1585152, scale_up=True): 30 | 31 | if scale_up: 32 | image_size = [im.shape[1] * 3 // 32 * 32, im.shape[0] * 3 // 32 * 32] 33 | else: 34 | image_size = [im.shape[1] // 32 * 32, im.shape[0] // 32 * 32] 35 | while image_size[0] * image_size[1] > max_size: 36 | image_size[0] /= 1.2 37 | image_size[1] /= 1.2 38 | image_size[0] = int(image_size[0] // 32) * 32 39 | image_size[1] = int(image_size[1] // 32) * 32 40 | 41 | 42 | resize_h = int(image_size[1]) 43 | resize_w = int(image_size[0]) 44 | 45 | 46 | scaled = cv2.resize(im, dsize=(resize_w, resize_h)) 47 | return scaled, (resize_h, resize_w) 48 | 49 | 50 | if __name__ == '__main__': 51 | 52 | parser = argparse.ArgumentParser() 53 | parser.add_argument('-cuda', type=int, default=1) 54 | parser.add_argument('-model', default='e2e-mlt.h5') 55 | parser.add_argument('-segm_thresh', default=0.5) 56 | 57 | font2 = ImageFont.truetype("Arial-Unicode-Regular.ttf", 18) 58 | 59 | args = parser.parse_args() 60 | 61 | net = ModelResNetSep2(attention=True) 62 | net_utils.load_net(args.model, net) 63 | net = net.eval() 64 | 65 | if args.cuda: 66 | print('Using cuda ...') 67 | net = net.cuda() 68 | 69 | cap = cv2.VideoCapture(0) 70 | cap.set(cv2.CAP_PROP_AUTOFOCUS, 1) 71 | ret, im = cap.read() 72 | 73 | frame_no = 0 74 | with torch.no_grad(): 75 | while ret: 76 | ret, im = cap.read() 77 | 78 | if ret==True: 79 | im_resized, (ratio_h, ratio_w) = resize_image(im, scale_up=False) 80 | images = np.asarray([im_resized], dtype=np.float) 81 | images /= 128 82 | images -= 1 83 | im_data = net_utils.np_to_variable(images, is_cuda=args.cuda).permute(0, 3, 1, 2) 84 | seg_pred, rboxs, angle_pred, features = net(im_data) 85 | 86 | rbox = rboxs[0].data.cpu()[0].numpy() 87 | rbox = rbox.swapaxes(0, 1) 88 | rbox = rbox.swapaxes(1, 2) 89 | 90 | angle_pred = angle_pred[0].data.cpu()[0].numpy() 91 | 92 | 93 | segm = seg_pred[0].data.cpu()[0].numpy() 94 | segm = segm.squeeze(0) 95 | 96 | draw2 = np.copy(im_resized) 97 | boxes = get_boxes(segm, rbox, angle_pred, args.segm_thresh) 98 | 99 | img = Image.fromarray(draw2) 100 | draw = ImageDraw.Draw(img) 101 | 102 | #if len(boxes) > 10: 103 | # boxes = boxes[0:10] 104 | 105 | out_boxes = [] 106 | for box in boxes: 107 | 108 | pts = box[0:8] 109 | pts = pts.reshape(4, -1) 110 | 111 | det_text, conf, dec_s = ocr_image(net, codec, im_data, box) 112 | if len(det_text) == 0: 113 | continue 114 | 115 | width, height = draw.textsize(det_text, font=font2) 116 | center = [box[0], box[1]] 117 | draw.text((center[0], center[1]), det_text, fill = (0,255,0),font=font2) 118 | out_boxes.append(box) 119 | print(det_text) 120 | 121 | im = np.array(img) 122 | for box in out_boxes: 123 | pts = box[0:8] 124 | pts = pts.reshape(4, -1) 125 | draw_box_points(im, pts, color=(0, 255, 0), thickness=1) 126 | 127 | cv2.imshow('img', im) 128 | cv2.waitKey(10) 129 | 130 | 131 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nvidia/cuda:9.0-cudnn7-devel 2 | 3 | # Install system packages 4 | RUN apt-get update && apt-get install -y --no-install-recommends \ 5 | software-properties-common && \ 6 | rm -rf /var/lib/apt/lists/* 7 | 8 | RUN add-apt-repository ppa:ubuntu-toolchain-r/test && \ 9 | apt-get update && \ 10 | apt-get install -y --no-install-recommends \ 11 | bzip2 \ 12 | build-essential \ 13 | gcc-6 \ 14 | g++-6 \ 15 | git \ 16 | cmake \ 17 | graphviz \ 18 | libgl1-mesa-glx \ 19 | libhdf5-dev \ 20 | openmpi-bin \ 21 | wget && \ 22 | rm -rf /var/lib/apt/lists/* 23 | 24 | # Install conda and related packages 25 | ENV CONDA_DIR /opt/conda 26 | ENV PATH $CONDA_DIR/bin:$PATH 27 | 28 | RUN wget --quiet --no-check-certificate https://repo.continuum.io/miniconda/Miniconda3-4.2.12-Linux-x86_64.sh && \ 29 | echo "c59b3dd3cad550ac7596e0d599b91e75d88826db132e4146030ef471bb434e9a *Miniconda3-4.2.12-Linux-x86_64.sh" | sha256sum -c - && \ 30 | /bin/bash /Miniconda3-4.2.12-Linux-x86_64.sh -f -b -p $CONDA_DIR && \ 31 | rm Miniconda3-4.2.12-Linux-x86_64.sh && \ 32 | echo export PATH=$CONDA_DIR/bin:'$PATH' > /etc/profile.d/conda.sh 33 | 34 | ARG python_version=3.6 35 | 36 | RUN conda install -y python=${python_version} && \ 37 | pip install --upgrade pip && \ 38 | pip install \ 39 | sklearn_pandas && \ 40 | conda install \ 41 | bcolz \ 42 | h5py \ 43 | matplotlib \ 44 | mkl \ 45 | nose \ 46 | notebook \ 47 | Pillow \ 48 | pandas \ 49 | pydot \ 50 | pygpu \ 51 | pyyaml \ 52 | scikit-learn \ 53 | six && \ 54 | conda clean -yt 55 | 56 | # Install oytorch 57 | RUN conda install torchvision pytorch=0.4.1 -c pytorch 58 | 59 | # Install Sean Naren's warp-ctc 60 | RUN git clone https://github.com/SeanNaren/warp-ctc.git 61 | RUN cd warp-ctc; mkdir build; cd build; cmake ..; make 62 | RUN cd warp-ctc; cd pytorch_binding; python setup.py install 63 | 64 | # We need gcc-6 and g++-6 to compile nms 65 | RUN rm -rf /usr/bin/gcc && rm -rf /usr/bin/g++ && \ 66 | ln -s /usr/bin/gcc-6 /usr/bin/gcc && \ 67 | ln -s /usr/bin/g++-6 /usr/bin/g++ 68 | 69 | # Install opencv3 Python bindings 70 | RUN apt-get update && apt-get install -y --no-install-recommends \ 71 | libgtk2.0-0 \ 72 | libcanberra-gtk-module && \ 73 | rm -rf /var/lib/apt/lists/* 74 | 75 | RUN conda install -y -c menpo opencv3=3.1.0 && \ 76 | conda clean -ya 77 | 78 | WORKDIR /workspace 79 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | Using Docker for Reproducible E2E-MLT Build Environment 2 | ======================================================= 3 | 4 | ## Prerequisite 5 | 6 | The following procedures are tested on machine with 7 | 8 | * Ubuntu 16.04.5 LTS 9 | * Docker version 17.12.0-ce, build c97c6d6 10 | * CUDA Version 8.0.61 11 | * CUDNN 7 12 | 13 | You'll also need to install [`nvidia-docker2`](https://github.com/NVIDIA/nvidia-docker). 14 | 15 | ## Instructions for running the demo 16 | 17 | 1. Inside this directory, run `. ./build_docker.sh` to build the docker image. The image will take up approximately 8GB. 18 | 2. After the image is built, first edit `PRETRAINED_MODEL_PATH` in `run_docker.sh` to the directory that contains the pretrained model `e2e-mlt.h5`. Next, run `. ./run_docker.sh`. 19 | 3. By default, you'll be inside `/workspace` directory, which contains all the files inside the E2E-MLT repo. 20 | -------------------------------------------------------------------------------- /docker/build_docker.sh: -------------------------------------------------------------------------------- 1 | docker build . --no-cache -t e2e-mlt -f ./Dockerfile 2 | -------------------------------------------------------------------------------- /docker/run_docker.sh: -------------------------------------------------------------------------------- 1 | PRETRAINED_MODEL_PATH=~/pretrained_models 2 | 3 | docker run --rm --shm-size 8G -it \ 4 | -v ${PRETRAINED_MODEL_PATH}:/pretrained_models \ 5 | -v `pwd`/../:/workspace \ 6 | --name e2e-mlt e2e-mlt:latest \ 7 | bash 8 | -------------------------------------------------------------------------------- /images/synth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichalBusta/E2E-MLT/fc79f9ab4c8c75c882fae12c399d1c5355bb8a1b/images/synth.png -------------------------------------------------------------------------------- /net_utils.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Aug 31, 2017 3 | 4 | @author: Michal.Busta at gmail.com 5 | ''' 6 | import numpy as np 7 | import torch 8 | from torch.autograd import Variable 9 | 10 | def np_to_variable(x, is_cuda=True, dtype=torch.FloatTensor): 11 | v = torch.from_numpy(x).type(dtype) 12 | if is_cuda: 13 | v = v.cuda() 14 | return v 15 | 16 | def load_net(fname, net, optimizer=None): 17 | sp = torch.load(fname) 18 | step = sp['step'] 19 | try: 20 | learning_rate = sp['learning_rate'] 21 | except: 22 | import traceback 23 | traceback.print_exc() 24 | learning_rate = 0.001 25 | opt_state = sp['optimizer'] 26 | sp = sp['state_dict'] 27 | for k, v in net.state_dict().items(): 28 | try: 29 | param = sp[k] 30 | v.copy_(param) 31 | except: 32 | import traceback 33 | traceback.print_exc() 34 | 35 | if optimizer is not None: 36 | try: 37 | optimizer.load_state_dict(opt_state) 38 | except: 39 | import traceback 40 | traceback.print_exc() 41 | 42 | print(fname) 43 | return step, learning_rate 44 | -------------------------------------------------------------------------------- /nms/.gitignore: -------------------------------------------------------------------------------- 1 | adaptor.so 2 | -------------------------------------------------------------------------------- /nms/Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS = -I include -std=c++11 -O3 $(shell python3-config --cflags) 2 | LDFLAGS = $(shell python3-config --ldflags) 3 | 4 | DEPS = nms.h $(shell find include -xtype f) 5 | CXX_SOURCES = adaptor.cpp include/clipper/clipper.cpp 6 | 7 | LIB_SO = adaptor.so 8 | 9 | $(LIB_SO): $(CXX_SOURCES) $(DEPS) 10 | $(CXX) -o $@ $(CXXFLAGS) $(LDFLAGS) $(CXX_SOURCES) --shared -fPIC 11 | 12 | clean: 13 | rm -rf $(LIB_SO) 14 | -------------------------------------------------------------------------------- /nms/__init__.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | import numpy as np 4 | 5 | BASE_DIR = os.path.dirname(os.path.realpath(__file__)) 6 | 7 | if subprocess.call(['make', '-C', BASE_DIR]) != 0: # return value 8 | raise RuntimeError('Cannot compile nms: {}'.format(BASE_DIR)) 9 | 10 | 11 | def do_nms(segm_map, geo_map, angle_pred, poly_map, thres=0.3, thres2=0.2, segm_thresh=0.5): 12 | precision=10000 13 | from .adaptor import do_nms as nms_impl 14 | ret = np.array(nms_impl(segm_map, geo_map, angle_pred, poly_map, thres, thres2, segm_thresh), dtype='float32') 15 | if len(ret) > 0: 16 | ret[:,:8] /= precision 17 | return ret 18 | 19 | 20 | def get_boxes(iou_map, rbox, angle_pred, segm_thresh=0.5): 21 | 22 | angle_pred = angle_pred.swapaxes(0, 1) 23 | angle_pred = angle_pred.swapaxes(1, 2) 24 | 25 | poly_map = np.zeros((iou_map.shape[0], iou_map.shape[1]), dtype = np.int32) 26 | poly_map.fill(-1); 27 | 28 | boxes = do_nms( iou_map, rbox, angle_pred, poly_map, 0.4, 0.2, segm_thresh) 29 | return boxes 30 | 31 | -------------------------------------------------------------------------------- /nms/adaptor.cpp: -------------------------------------------------------------------------------- 1 | #include "../nms/include/pybind11/numpy.h" 2 | #include "../nms/include/pybind11/pybind11.h" 3 | #include "../nms/include/pybind11/stl.h" 4 | #include "../nms/include/pybind11/stl_bind.h" 5 | #include "../nms/nms.h" 6 | 7 | namespace py = pybind11; 8 | 9 | namespace cl = ClipperLib; 10 | 11 | namespace nms_adaptor { 12 | 13 | std::vector> polys2floats(std::vector &polys) { 14 | std::vector> ret; 15 | for (size_t i = 0; i < polys.size(); i ++) { 16 | auto &p = polys[i]; 17 | auto &poly = p.poly; 18 | 19 | ret.emplace_back(std::vector{ 20 | float(poly[0].X), float(poly[0].Y), 21 | float(poly[1].X), float(poly[1].Y), 22 | float(poly[2].X), float(poly[2].Y), 23 | float(poly[3].X), float(poly[3].Y), 24 | float(p.score), float(p.nr_polys) 25 | }); 26 | } 27 | 28 | return ret; 29 | } 30 | 31 | /** 32 | * 33 | * \param quad_n9 an n-by-9 numpy array, where first 8 numbers denote the 34 | * quadrangle, and the last one is the score 35 | * \param iou_threshold two quadrangles with iou score above this threshold 36 | * will be merged 37 | * 38 | * \return an n-by-9 numpy array, the merged quadrangles 39 | */ 40 | std::vector> do_nms( 41 | py::array_t segm, 42 | py::array_t geo_map, 43 | py::array_t angle, 44 | py::array_t poly_map, 45 | float iou_threshold, float iou_threshold2, float segm_threshold) { 46 | auto ibuf = segm.request(); 47 | auto pbuf = geo_map.request(); 48 | auto abuf = angle.request(); 49 | auto poly_buff = poly_map.request(); 50 | if (pbuf.ndim != 3) 51 | throw std::runtime_error("geometry map must have a shape of (h x w x 4)"); 52 | if (ibuf.ndim != 2) 53 | throw std::runtime_error("segmentation have a shape of (h x w)"); 54 | if (abuf.ndim != 3) 55 | throw std::runtime_error("angle have a shape of (h x w x 2)"); 56 | if (poly_buff.ndim != 2) 57 | throw std::runtime_error("polygon buffer have a shape of (h x w)"); 58 | 59 | //TODO we are missing a lot of asserts ... 60 | 61 | int w = ibuf.shape[1]; 62 | int h = ibuf.shape[0]; 63 | int offset = 0; 64 | int rstride = w * 4; 65 | int astride = w * 2; 66 | float* iptr = static_cast(ibuf.ptr); 67 | float* rptr = static_cast(pbuf.ptr); 68 | float* aptr = static_cast(abuf.ptr); 69 | int* poly_ptr = static_cast(poly_buff.ptr); 70 | float scale_factor = 4; 71 | 72 | float precision = 10000; 73 | 74 | std::vector polys; 75 | using cInt = cl::cInt; 76 | for(int y = 0; y < h; y++){ 77 | for(int x = 0; x < w; x++){ 78 | auto p = iptr + offset; 79 | auto r = rptr + y * rstride + x * 4; 80 | auto a = aptr + y * astride + x * 2; 81 | if( *p > segm_threshold ){ 82 | float angle_cos = a[1]; 83 | float angle_sin = a[0]; 84 | 85 | float xp = x + 0.25f; 86 | float yp = y + 0.25f; 87 | 88 | float pos_r_x = (xp - r[2] * angle_cos) * scale_factor; 89 | float pos_r_y = (yp - r[2] * angle_sin) * scale_factor; 90 | float pos_r2_x = (xp + r[3] * angle_cos) * scale_factor; 91 | float pos_r2_y = (yp + r[3] * angle_sin) * scale_factor; 92 | 93 | float ph = 9;// (r[0] + r[1]) + 1e-5; 94 | float phx = 9; 95 | 96 | float p_left = expf(-r[2] / phx); 97 | float p_top = expf(-r[0] / ph); 98 | float p_right = expf(-r[3] / phx); 99 | float p_bt = expf(-r[1] / ph); 100 | 101 | nms::Polygon poly{ 102 | { 103 | {cInt(roundf(precision * (pos_r_x - r[1] * angle_sin * scale_factor))), cInt(roundf(precision * (pos_r_y + r[1] * angle_cos * scale_factor)))}, 104 | {cInt(roundf(precision * (pos_r_x + r[0] * angle_sin * scale_factor ))), cInt(roundf(precision * (pos_r_y - r[0] * angle_cos * scale_factor)))}, 105 | {cInt(roundf(precision * (pos_r2_x + r[0] * angle_sin * scale_factor))), cInt(roundf(precision * (pos_r2_y - r[0] * angle_cos * scale_factor)))}, 106 | {cInt(roundf(precision * (pos_r2_x - r[1] * angle_sin * scale_factor))), cInt(roundf(precision * (pos_r2_y + r[1] * angle_cos * scale_factor)))}, 107 | }, 108 | p[0], 109 | {p_left * p_bt, p_left * p_top, p_right * p_top, p_right * p_bt}, 110 | x, 111 | y, 112 | 1 113 | }; 114 | polys.push_back(poly); 115 | } 116 | offset++; 117 | } 118 | } 119 | std::vector poly_out = nms::merge_iou(polys, poly_ptr, w, h, iou_threshold, iou_threshold2); 120 | return polys2floats(poly_out); 121 | } 122 | 123 | } 124 | 125 | PYBIND11_MODULE(adaptor, m) { 126 | 127 | m.def("do_nms", &nms_adaptor::do_nms, 128 | "perform non-maxima suppression"); 129 | } 130 | 131 | -------------------------------------------------------------------------------- /nms/include/clipper/clipper.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * * 3 | * Author : Angus Johnson * 4 | * Version : 6.4.0 * 5 | * Date : 2 July 2015 * 6 | * Website : http://www.angusj.com * 7 | * Copyright : Angus Johnson 2010-2015 * 8 | * * 9 | * License: * 10 | * Use, modification & distribution is subject to Boost Software License Ver 1. * 11 | * http://www.boost.org/LICENSE_1_0.txt * 12 | * * 13 | * Attributions: * 14 | * The code in this library is an extension of Bala Vatti's clipping algorithm: * 15 | * "A generic solution to polygon clipping" * 16 | * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * 17 | * http://portal.acm.org/citation.cfm?id=129906 * 18 | * * 19 | * Computer graphics and geometric modeling: implementation and algorithms * 20 | * By Max K. Agoston * 21 | * Springer; 1 edition (January 4, 2005) * 22 | * http://books.google.com/books?q=vatti+clipping+agoston * 23 | * * 24 | * See also: * 25 | * "Polygon Offsetting by Computing Winding Numbers" * 26 | * Paper no. DETC2005-85513 pp. 565-575 * 27 | * ASME 2005 International Design Engineering Technical Conferences * 28 | * and Computers and Information in Engineering Conference (IDETC/CIE2005) * 29 | * September 24-28, 2005 , Long Beach, California, USA * 30 | * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * 31 | * * 32 | *******************************************************************************/ 33 | 34 | #ifndef clipper_hpp 35 | #define clipper_hpp 36 | 37 | #define CLIPPER_VERSION "6.2.6" 38 | 39 | //use_int32: When enabled 32bit ints are used instead of 64bit ints. This 40 | //improve performance but coordinate values are limited to the range +/- 46340 41 | //#define use_int32 42 | 43 | //use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance. 44 | //#define use_xyz 45 | 46 | //use_lines: Enables line clipping. Adds a very minor cost to performance. 47 | #define use_lines 48 | 49 | //use_deprecated: Enables temporary support for the obsolete functions 50 | //#define use_deprecated 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | namespace ClipperLib { 63 | 64 | enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; 65 | enum PolyType { ptSubject, ptClip }; 66 | //By far the most widely used winding rules for polygon filling are 67 | //EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) 68 | //Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) 69 | //see http://glprogramming.com/red/chapter11.html 70 | enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; 71 | 72 | #ifdef use_int32 73 | typedef int cInt; 74 | static cInt const loRange = 0x7FFF; 75 | static cInt const hiRange = 0x7FFF; 76 | #else 77 | typedef signed long long cInt; 78 | static cInt const loRange = 0x3FFFFFFF; 79 | static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; 80 | typedef signed long long long64; //used by Int128 class 81 | typedef unsigned long long ulong64; 82 | 83 | #endif 84 | 85 | struct IntPoint { 86 | cInt X; 87 | cInt Y; 88 | #ifdef use_xyz 89 | cInt Z; 90 | IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {}; 91 | #else 92 | IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {}; 93 | #endif 94 | 95 | friend inline bool operator== (const IntPoint& a, const IntPoint& b) 96 | { 97 | return a.X == b.X && a.Y == b.Y; 98 | } 99 | friend inline bool operator!= (const IntPoint& a, const IntPoint& b) 100 | { 101 | return a.X != b.X || a.Y != b.Y; 102 | } 103 | }; 104 | //------------------------------------------------------------------------------ 105 | 106 | typedef std::vector< IntPoint > Path; 107 | typedef std::vector< Path > Paths; 108 | 109 | inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;} 110 | inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;} 111 | 112 | std::ostream& operator <<(std::ostream &s, const IntPoint &p); 113 | std::ostream& operator <<(std::ostream &s, const Path &p); 114 | std::ostream& operator <<(std::ostream &s, const Paths &p); 115 | 116 | struct DoublePoint 117 | { 118 | double X; 119 | double Y; 120 | DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} 121 | DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {} 122 | }; 123 | //------------------------------------------------------------------------------ 124 | 125 | #ifdef use_xyz 126 | typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt); 127 | #endif 128 | 129 | enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4}; 130 | enum JoinType {jtSquare, jtRound, jtMiter}; 131 | enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound}; 132 | 133 | class PolyNode; 134 | typedef std::vector< PolyNode* > PolyNodes; 135 | 136 | class PolyNode 137 | { 138 | public: 139 | PolyNode(); 140 | virtual ~PolyNode(){}; 141 | Path Contour; 142 | PolyNodes Childs; 143 | PolyNode* Parent; 144 | PolyNode* GetNext() const; 145 | bool IsHole() const; 146 | bool IsOpen() const; 147 | int ChildCount() const; 148 | private: 149 | unsigned Index; //node index in Parent.Childs 150 | bool m_IsOpen; 151 | JoinType m_jointype; 152 | EndType m_endtype; 153 | PolyNode* GetNextSiblingUp() const; 154 | void AddChild(PolyNode& child); 155 | friend class Clipper; //to access Index 156 | friend class ClipperOffset; 157 | }; 158 | 159 | class PolyTree: public PolyNode 160 | { 161 | public: 162 | ~PolyTree(){Clear();}; 163 | PolyNode* GetFirst() const; 164 | void Clear(); 165 | int Total() const; 166 | private: 167 | PolyNodes AllNodes; 168 | friend class Clipper; //to access AllNodes 169 | }; 170 | 171 | bool Orientation(const Path &poly); 172 | double Area(const Path &poly); 173 | int PointInPolygon(const IntPoint &pt, const Path &path); 174 | 175 | void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); 176 | void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); 177 | void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); 178 | 179 | void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); 180 | void CleanPolygon(Path& poly, double distance = 1.415); 181 | void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415); 182 | void CleanPolygons(Paths& polys, double distance = 1.415); 183 | 184 | void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed); 185 | void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed); 186 | void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution); 187 | 188 | void PolyTreeToPaths(const PolyTree& polytree, Paths& paths); 189 | void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths); 190 | void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths); 191 | 192 | void ReversePath(Path& p); 193 | void ReversePaths(Paths& p); 194 | 195 | struct IntRect { cInt left; cInt top; cInt right; cInt bottom; }; 196 | 197 | //enums that are used internally ... 198 | enum EdgeSide { esLeft = 1, esRight = 2}; 199 | 200 | //forward declarations (for stuff used internally) ... 201 | struct TEdge; 202 | struct IntersectNode; 203 | struct LocalMinimum; 204 | struct OutPt; 205 | struct OutRec; 206 | struct Join; 207 | 208 | typedef std::vector < OutRec* > PolyOutList; 209 | typedef std::vector < TEdge* > EdgeList; 210 | typedef std::vector < Join* > JoinList; 211 | typedef std::vector < IntersectNode* > IntersectList; 212 | 213 | //------------------------------------------------------------------------------ 214 | 215 | //ClipperBase is the ancestor to the Clipper class. It should not be 216 | //instantiated directly. This class simply abstracts the conversion of sets of 217 | //polygon coordinates into edge objects that are stored in a LocalMinima list. 218 | class ClipperBase 219 | { 220 | public: 221 | ClipperBase(); 222 | virtual ~ClipperBase(); 223 | virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); 224 | bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); 225 | virtual void Clear(); 226 | IntRect GetBounds(); 227 | bool PreserveCollinear() {return m_PreserveCollinear;}; 228 | void PreserveCollinear(bool value) {m_PreserveCollinear = value;}; 229 | protected: 230 | void DisposeLocalMinimaList(); 231 | TEdge* AddBoundsToLML(TEdge *e, bool IsClosed); 232 | virtual void Reset(); 233 | TEdge* ProcessBound(TEdge* E, bool IsClockwise); 234 | void InsertScanbeam(const cInt Y); 235 | bool PopScanbeam(cInt &Y); 236 | bool LocalMinimaPending(); 237 | bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin); 238 | OutRec* CreateOutRec(); 239 | void DisposeAllOutRecs(); 240 | void DisposeOutRec(PolyOutList::size_type index); 241 | void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); 242 | void DeleteFromAEL(TEdge *e); 243 | void UpdateEdgeIntoAEL(TEdge *&e); 244 | 245 | typedef std::vector MinimaList; 246 | MinimaList::iterator m_CurrentLM; 247 | MinimaList m_MinimaList; 248 | 249 | bool m_UseFullRange; 250 | EdgeList m_edges; 251 | bool m_PreserveCollinear; 252 | bool m_HasOpenPaths; 253 | PolyOutList m_PolyOuts; 254 | TEdge *m_ActiveEdges; 255 | 256 | typedef std::priority_queue ScanbeamList; 257 | ScanbeamList m_Scanbeam; 258 | }; 259 | //------------------------------------------------------------------------------ 260 | 261 | class Clipper : public virtual ClipperBase 262 | { 263 | public: 264 | Clipper(int initOptions = 0); 265 | bool Execute(ClipType clipType, 266 | Paths &solution, 267 | PolyFillType fillType = pftEvenOdd); 268 | bool Execute(ClipType clipType, 269 | Paths &solution, 270 | PolyFillType subjFillType, 271 | PolyFillType clipFillType); 272 | bool Execute(ClipType clipType, 273 | PolyTree &polytree, 274 | PolyFillType fillType = pftEvenOdd); 275 | bool Execute(ClipType clipType, 276 | PolyTree &polytree, 277 | PolyFillType subjFillType, 278 | PolyFillType clipFillType); 279 | bool ReverseSolution() { return m_ReverseOutput; }; 280 | void ReverseSolution(bool value) {m_ReverseOutput = value;}; 281 | bool StrictlySimple() {return m_StrictSimple;}; 282 | void StrictlySimple(bool value) {m_StrictSimple = value;}; 283 | //set the callback function for z value filling on intersections (otherwise Z is 0) 284 | #ifdef use_xyz 285 | void ZFillFunction(ZFillCallback zFillFunc); 286 | #endif 287 | protected: 288 | virtual bool ExecuteInternal(); 289 | private: 290 | JoinList m_Joins; 291 | JoinList m_GhostJoins; 292 | IntersectList m_IntersectList; 293 | ClipType m_ClipType; 294 | typedef std::list MaximaList; 295 | MaximaList m_Maxima; 296 | TEdge *m_SortedEdges; 297 | bool m_ExecuteLocked; 298 | PolyFillType m_ClipFillType; 299 | PolyFillType m_SubjFillType; 300 | bool m_ReverseOutput; 301 | bool m_UsingPolyTree; 302 | bool m_StrictSimple; 303 | #ifdef use_xyz 304 | ZFillCallback m_ZFill; //custom callback 305 | #endif 306 | void SetWindingCount(TEdge& edge); 307 | bool IsEvenOddFillType(const TEdge& edge) const; 308 | bool IsEvenOddAltFillType(const TEdge& edge) const; 309 | void InsertLocalMinimaIntoAEL(const cInt botY); 310 | void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge); 311 | void AddEdgeToSEL(TEdge *edge); 312 | bool PopEdgeFromSEL(TEdge *&edge); 313 | void CopyAELToSEL(); 314 | void DeleteFromSEL(TEdge *e); 315 | void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); 316 | bool IsContributing(const TEdge& edge) const; 317 | bool IsTopHorz(const cInt XPos); 318 | void DoMaxima(TEdge *e); 319 | void ProcessHorizontals(); 320 | void ProcessHorizontal(TEdge *horzEdge); 321 | void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); 322 | OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); 323 | OutRec* GetOutRec(int idx); 324 | void AppendPolygon(TEdge *e1, TEdge *e2); 325 | void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt); 326 | OutPt* AddOutPt(TEdge *e, const IntPoint &pt); 327 | OutPt* GetLastOutPt(TEdge *e); 328 | bool ProcessIntersections(const cInt topY); 329 | void BuildIntersectList(const cInt topY); 330 | void ProcessIntersectList(); 331 | void ProcessEdgesAtTopOfScanbeam(const cInt topY); 332 | void BuildResult(Paths& polys); 333 | void BuildResult2(PolyTree& polytree); 334 | void SetHoleState(TEdge *e, OutRec *outrec); 335 | void DisposeIntersectNodes(); 336 | bool FixupIntersectionOrder(); 337 | void FixupOutPolygon(OutRec &outrec); 338 | void FixupOutPolyline(OutRec &outrec); 339 | bool IsHole(TEdge *e); 340 | bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl); 341 | void FixHoleLinkage(OutRec &outrec); 342 | void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt); 343 | void ClearJoins(); 344 | void ClearGhostJoins(); 345 | void AddGhostJoin(OutPt *op, const IntPoint offPt); 346 | bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2); 347 | void JoinCommonEdges(); 348 | void DoSimplePolygons(); 349 | void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); 350 | void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec); 351 | void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec); 352 | #ifdef use_xyz 353 | void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2); 354 | #endif 355 | }; 356 | //------------------------------------------------------------------------------ 357 | 358 | class ClipperOffset 359 | { 360 | public: 361 | ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25); 362 | ~ClipperOffset(); 363 | void AddPath(const Path& path, JoinType joinType, EndType endType); 364 | void AddPaths(const Paths& paths, JoinType joinType, EndType endType); 365 | void Execute(Paths& solution, double delta); 366 | void Execute(PolyTree& solution, double delta); 367 | void Clear(); 368 | double MiterLimit; 369 | double ArcTolerance; 370 | private: 371 | Paths m_destPolys; 372 | Path m_srcPoly; 373 | Path m_destPoly; 374 | std::vector m_normals; 375 | double m_delta, m_sinA, m_sin, m_cos; 376 | double m_miterLim, m_StepsPerRad; 377 | IntPoint m_lowest; 378 | PolyNode m_polyNodes; 379 | 380 | void FixOrientations(); 381 | void DoOffset(double delta); 382 | void OffsetPoint(int j, int& k, JoinType jointype); 383 | void DoSquare(int j, int k); 384 | void DoMiter(int j, int k, double r); 385 | void DoRound(int j, int k); 386 | }; 387 | //------------------------------------------------------------------------------ 388 | 389 | class clipperException : public std::exception 390 | { 391 | public: 392 | clipperException(const char* description): m_descr(description) {} 393 | virtual ~clipperException() throw() {} 394 | virtual const char* what() const throw() {return m_descr.c_str();} 395 | private: 396 | std::string m_descr; 397 | }; 398 | //------------------------------------------------------------------------------ 399 | 400 | } //ClipperLib namespace 401 | 402 | #endif //clipper_hpp 403 | 404 | 405 | -------------------------------------------------------------------------------- /nms/include/pybind11/attr.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/attr.h: Infrastructure for processing custom 3 | type and function attributes 4 | 5 | Copyright (c) 2016 Wenzel Jakob 6 | 7 | All rights reserved. Use of this source code is governed by a 8 | BSD-style license that can be found in the LICENSE file. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "../../../nms/include/pybind11/cast.h" 14 | 15 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 16 | 17 | /// \addtogroup annotations 18 | /// @{ 19 | 20 | /// Annotation for methods 21 | struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; 22 | 23 | /// Annotation for operators 24 | struct is_operator { }; 25 | 26 | /// Annotation for parent scope 27 | struct scope { handle value; scope(const handle &s) : value(s) { } }; 28 | 29 | /// Annotation for documentation 30 | struct doc { const char *value; doc(const char *value) : value(value) { } }; 31 | 32 | /// Annotation for function names 33 | struct name { const char *value; name(const char *value) : value(value) { } }; 34 | 35 | /// Annotation indicating that a function is an overload associated with a given "sibling" 36 | struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } }; 37 | 38 | /// Annotation indicating that a class derives from another given type 39 | template struct base { 40 | PYBIND11_DEPRECATED("base() was deprecated in favor of specifying 'T' as a template argument to class_") 41 | base() { } 42 | }; 43 | 44 | /// Keep patient alive while nurse lives 45 | template struct keep_alive { }; 46 | 47 | /// Annotation indicating that a class is involved in a multiple inheritance relationship 48 | struct multiple_inheritance { }; 49 | 50 | /// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class 51 | struct dynamic_attr { }; 52 | 53 | /// Annotation which enables the buffer protocol for a type 54 | struct buffer_protocol { }; 55 | 56 | /// Annotation which requests that a special metaclass is created for a type 57 | struct metaclass { 58 | handle value; 59 | 60 | PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") 61 | metaclass() {} 62 | 63 | /// Override pybind11's default metaclass 64 | explicit metaclass(handle value) : value(value) { } 65 | }; 66 | 67 | /// Annotation that marks a class as local to the module: 68 | struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } }; 69 | 70 | /// Annotation to mark enums as an arithmetic type 71 | struct arithmetic { }; 72 | 73 | /** \rst 74 | A call policy which places one or more guard variables (``Ts...``) around the function call. 75 | 76 | For example, this definition: 77 | 78 | .. code-block:: cpp 79 | 80 | m.def("foo", foo, py::call_guard()); 81 | 82 | is equivalent to the following pseudocode: 83 | 84 | .. code-block:: cpp 85 | 86 | m.def("foo", [](args...) { 87 | T scope_guard; 88 | return foo(args...); // forwarded arguments 89 | }); 90 | \endrst */ 91 | template struct call_guard; 92 | 93 | template <> struct call_guard<> { using type = detail::void_type; }; 94 | 95 | template 96 | struct call_guard { 97 | static_assert(std::is_default_constructible::value, 98 | "The guard type must be default constructible"); 99 | 100 | using type = T; 101 | }; 102 | 103 | template 104 | struct call_guard { 105 | struct type { 106 | T guard{}; // Compose multiple guard types with left-to-right default-constructor order 107 | typename call_guard::type next{}; 108 | }; 109 | }; 110 | 111 | /// @} annotations 112 | 113 | NAMESPACE_BEGIN(detail) 114 | /* Forward declarations */ 115 | enum op_id : int; 116 | enum op_type : int; 117 | struct undefined_t; 118 | template struct op_; 119 | inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret); 120 | 121 | /// Internal data structure which holds metadata about a keyword argument 122 | struct argument_record { 123 | const char *name; ///< Argument name 124 | const char *descr; ///< Human-readable version of the argument value 125 | handle value; ///< Associated Python object 126 | bool convert : 1; ///< True if the argument is allowed to convert when loading 127 | bool none : 1; ///< True if None is allowed when loading 128 | 129 | argument_record(const char *name, const char *descr, handle value, bool convert, bool none) 130 | : name(name), descr(descr), value(value), convert(convert), none(none) { } 131 | }; 132 | 133 | /// Internal data structure which holds metadata about a bound function (signature, overloads, etc.) 134 | struct function_record { 135 | function_record() 136 | : is_constructor(false), is_new_style_constructor(false), is_stateless(false), 137 | is_operator(false), has_args(false), has_kwargs(false), is_method(false) { } 138 | 139 | /// Function name 140 | char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ 141 | 142 | // User-specified documentation string 143 | char *doc = nullptr; 144 | 145 | /// Human-readable version of the function signature 146 | char *signature = nullptr; 147 | 148 | /// List of registered keyword arguments 149 | std::vector args; 150 | 151 | /// Pointer to lambda function which converts arguments and performs the actual call 152 | handle (*impl) (function_call &) = nullptr; 153 | 154 | /// Storage for the wrapped function pointer and captured data, if any 155 | void *data[3] = { }; 156 | 157 | /// Pointer to custom destructor for 'data' (if needed) 158 | void (*free_data) (function_record *ptr) = nullptr; 159 | 160 | /// Return value policy associated with this function 161 | return_value_policy policy = return_value_policy::automatic; 162 | 163 | /// True if name == '__init__' 164 | bool is_constructor : 1; 165 | 166 | /// True if this is a new-style `__init__` defined in `detail/init.h` 167 | bool is_new_style_constructor : 1; 168 | 169 | /// True if this is a stateless function pointer 170 | bool is_stateless : 1; 171 | 172 | /// True if this is an operator (__add__), etc. 173 | bool is_operator : 1; 174 | 175 | /// True if the function has a '*args' argument 176 | bool has_args : 1; 177 | 178 | /// True if the function has a '**kwargs' argument 179 | bool has_kwargs : 1; 180 | 181 | /// True if this is a method 182 | bool is_method : 1; 183 | 184 | /// Number of arguments (including py::args and/or py::kwargs, if present) 185 | std::uint16_t nargs; 186 | 187 | /// Python method object 188 | PyMethodDef *def = nullptr; 189 | 190 | /// Python handle to the parent scope (a class or a module) 191 | handle scope; 192 | 193 | /// Python handle to the sibling function representing an overload chain 194 | handle sibling; 195 | 196 | /// Pointer to next overload 197 | function_record *next = nullptr; 198 | }; 199 | 200 | /// Special data structure which (temporarily) holds metadata about a bound class 201 | struct type_record { 202 | PYBIND11_NOINLINE type_record() 203 | : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), module_local(false) { } 204 | 205 | /// Handle to the parent scope 206 | handle scope; 207 | 208 | /// Name of the class 209 | const char *name = nullptr; 210 | 211 | // Pointer to RTTI type_info data structure 212 | const std::type_info *type = nullptr; 213 | 214 | /// How large is the underlying C++ type? 215 | size_t type_size = 0; 216 | 217 | /// How large is the type's holder? 218 | size_t holder_size = 0; 219 | 220 | /// The global operator new can be overridden with a class-specific variant 221 | void *(*operator_new)(size_t) = ::operator new; 222 | 223 | /// Function pointer to class_<..>::init_instance 224 | void (*init_instance)(instance *, const void *) = nullptr; 225 | 226 | /// Function pointer to class_<..>::dealloc 227 | void (*dealloc)(detail::value_and_holder &) = nullptr; 228 | 229 | /// List of base classes of the newly created type 230 | list bases; 231 | 232 | /// Optional docstring 233 | const char *doc = nullptr; 234 | 235 | /// Custom metaclass (optional) 236 | handle metaclass; 237 | 238 | /// Multiple inheritance marker 239 | bool multiple_inheritance : 1; 240 | 241 | /// Does the class manage a __dict__? 242 | bool dynamic_attr : 1; 243 | 244 | /// Does the class implement the buffer protocol? 245 | bool buffer_protocol : 1; 246 | 247 | /// Is the default (unique_ptr) holder type used? 248 | bool default_holder : 1; 249 | 250 | /// Is the class definition local to the module shared object? 251 | bool module_local : 1; 252 | 253 | PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) { 254 | auto base_info = detail::get_type_info(base, false); 255 | if (!base_info) { 256 | std::string tname(base.name()); 257 | detail::clean_type_id(tname); 258 | pybind11_fail("generic_type: type \"" + std::string(name) + 259 | "\" referenced unknown base type \"" + tname + "\""); 260 | } 261 | 262 | if (default_holder != base_info->default_holder) { 263 | std::string tname(base.name()); 264 | detail::clean_type_id(tname); 265 | pybind11_fail("generic_type: type \"" + std::string(name) + "\" " + 266 | (default_holder ? "does not have" : "has") + 267 | " a non-default holder type while its base \"" + tname + "\" " + 268 | (base_info->default_holder ? "does not" : "does")); 269 | } 270 | 271 | bases.append((PyObject *) base_info->type); 272 | 273 | if (base_info->type->tp_dictoffset != 0) 274 | dynamic_attr = true; 275 | 276 | if (caster) 277 | base_info->implicit_casts.emplace_back(type, caster); 278 | } 279 | }; 280 | 281 | inline function_call::function_call(function_record &f, handle p) : 282 | func(f), parent(p) { 283 | args.reserve(f.nargs); 284 | args_convert.reserve(f.nargs); 285 | } 286 | 287 | /// Tag for a new-style `__init__` defined in `detail/init.h` 288 | struct is_new_style_constructor { }; 289 | 290 | /** 291 | * Partial template specializations to process custom attributes provided to 292 | * cpp_function_ and class_. These are either used to initialize the respective 293 | * fields in the type_record and function_record data structures or executed at 294 | * runtime to deal with custom call policies (e.g. keep_alive). 295 | */ 296 | template struct process_attribute; 297 | 298 | template struct process_attribute_default { 299 | /// Default implementation: do nothing 300 | static void init(const T &, function_record *) { } 301 | static void init(const T &, type_record *) { } 302 | static void precall(function_call &) { } 303 | static void postcall(function_call &, handle) { } 304 | }; 305 | 306 | /// Process an attribute specifying the function's name 307 | template <> struct process_attribute : process_attribute_default { 308 | static void init(const name &n, function_record *r) { r->name = const_cast(n.value); } 309 | }; 310 | 311 | /// Process an attribute specifying the function's docstring 312 | template <> struct process_attribute : process_attribute_default { 313 | static void init(const doc &n, function_record *r) { r->doc = const_cast(n.value); } 314 | }; 315 | 316 | /// Process an attribute specifying the function's docstring (provided as a C-style string) 317 | template <> struct process_attribute : process_attribute_default { 318 | static void init(const char *d, function_record *r) { r->doc = const_cast(d); } 319 | static void init(const char *d, type_record *r) { r->doc = const_cast(d); } 320 | }; 321 | template <> struct process_attribute : process_attribute { }; 322 | 323 | /// Process an attribute indicating the function's return value policy 324 | template <> struct process_attribute : process_attribute_default { 325 | static void init(const return_value_policy &p, function_record *r) { r->policy = p; } 326 | }; 327 | 328 | /// Process an attribute which indicates that this is an overloaded function associated with a given sibling 329 | template <> struct process_attribute : process_attribute_default { 330 | static void init(const sibling &s, function_record *r) { r->sibling = s.value; } 331 | }; 332 | 333 | /// Process an attribute which indicates that this function is a method 334 | template <> struct process_attribute : process_attribute_default { 335 | static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; } 336 | }; 337 | 338 | /// Process an attribute which indicates the parent scope of a method 339 | template <> struct process_attribute : process_attribute_default { 340 | static void init(const scope &s, function_record *r) { r->scope = s.value; } 341 | }; 342 | 343 | /// Process an attribute which indicates that this function is an operator 344 | template <> struct process_attribute : process_attribute_default { 345 | static void init(const is_operator &, function_record *r) { r->is_operator = true; } 346 | }; 347 | 348 | template <> struct process_attribute : process_attribute_default { 349 | static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; } 350 | }; 351 | 352 | /// Process a keyword argument attribute (*without* a default value) 353 | template <> struct process_attribute : process_attribute_default { 354 | static void init(const arg &a, function_record *r) { 355 | if (r->is_method && r->args.empty()) 356 | r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/); 357 | r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); 358 | } 359 | }; 360 | 361 | /// Process a keyword argument attribute (*with* a default value) 362 | template <> struct process_attribute : process_attribute_default { 363 | static void init(const arg_v &a, function_record *r) { 364 | if (r->is_method && r->args.empty()) 365 | r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/); 366 | 367 | if (!a.value) { 368 | #if !defined(NDEBUG) 369 | std::string descr("'"); 370 | if (a.name) descr += std::string(a.name) + ": "; 371 | descr += a.type + "'"; 372 | if (r->is_method) { 373 | if (r->name) 374 | descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'"; 375 | else 376 | descr += " in method of '" + (std::string) str(r->scope) + "'"; 377 | } else if (r->name) { 378 | descr += " in function '" + (std::string) r->name + "'"; 379 | } 380 | pybind11_fail("arg(): could not convert default argument " 381 | + descr + " into a Python object (type not registered yet?)"); 382 | #else 383 | pybind11_fail("arg(): could not convert default argument " 384 | "into a Python object (type not registered yet?). " 385 | "Compile in debug mode for more information."); 386 | #endif 387 | } 388 | r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); 389 | } 390 | }; 391 | 392 | /// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that) 393 | template 394 | struct process_attribute::value>> : process_attribute_default { 395 | static void init(const handle &h, type_record *r) { r->bases.append(h); } 396 | }; 397 | 398 | /// Process a parent class attribute (deprecated, does not support multiple inheritance) 399 | template 400 | struct process_attribute> : process_attribute_default> { 401 | static void init(const base &, type_record *r) { r->add_base(typeid(T), nullptr); } 402 | }; 403 | 404 | /// Process a multiple inheritance attribute 405 | template <> 406 | struct process_attribute : process_attribute_default { 407 | static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; } 408 | }; 409 | 410 | template <> 411 | struct process_attribute : process_attribute_default { 412 | static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; } 413 | }; 414 | 415 | template <> 416 | struct process_attribute : process_attribute_default { 417 | static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; } 418 | }; 419 | 420 | template <> 421 | struct process_attribute : process_attribute_default { 422 | static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; } 423 | }; 424 | 425 | template <> 426 | struct process_attribute : process_attribute_default { 427 | static void init(const module_local &l, type_record *r) { r->module_local = l.value; } 428 | }; 429 | 430 | /// Process an 'arithmetic' attribute for enums (does nothing here) 431 | template <> 432 | struct process_attribute : process_attribute_default {}; 433 | 434 | template 435 | struct process_attribute> : process_attribute_default> { }; 436 | 437 | /** 438 | * Process a keep_alive call policy -- invokes keep_alive_impl during the 439 | * pre-call handler if both Nurse, Patient != 0 and use the post-call handler 440 | * otherwise 441 | */ 442 | template struct process_attribute> : public process_attribute_default> { 443 | template = 0> 444 | static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); } 445 | template = 0> 446 | static void postcall(function_call &, handle) { } 447 | template = 0> 448 | static void precall(function_call &) { } 449 | template = 0> 450 | static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); } 451 | }; 452 | 453 | /// Recursively iterate over variadic template arguments 454 | template struct process_attributes { 455 | static void init(const Args&... args, function_record *r) { 456 | int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; 457 | ignore_unused(unused); 458 | } 459 | static void init(const Args&... args, type_record *r) { 460 | int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; 461 | ignore_unused(unused); 462 | } 463 | static void precall(function_call &call) { 464 | int unused[] = { 0, (process_attribute::type>::precall(call), 0) ... }; 465 | ignore_unused(unused); 466 | } 467 | static void postcall(function_call &call, handle fn_ret) { 468 | int unused[] = { 0, (process_attribute::type>::postcall(call, fn_ret), 0) ... }; 469 | ignore_unused(unused); 470 | } 471 | }; 472 | 473 | template 474 | using is_call_guard = is_instantiation; 475 | 476 | /// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found) 477 | template 478 | using extract_guard_t = typename exactly_one_t, Extra...>::type; 479 | 480 | /// Check the number of named arguments at compile time 481 | template ::value...), 483 | size_t self = constexpr_sum(std::is_same::value...)> 484 | constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { 485 | return named == 0 || (self + named + has_args + has_kwargs) == nargs; 486 | } 487 | 488 | NAMESPACE_END(detail) 489 | NAMESPACE_END(PYBIND11_NAMESPACE) 490 | -------------------------------------------------------------------------------- /nms/include/pybind11/buffer_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/buffer_info.h: Python buffer object interface 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "../../../nms/include/pybind11/detail/common.h" 13 | 14 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 15 | 16 | /// Information record describing a Python buffer object 17 | struct buffer_info { 18 | void *ptr = nullptr; // Pointer to the underlying storage 19 | ssize_t itemsize = 0; // Size of individual items in bytes 20 | ssize_t size = 0; // Total number of entries 21 | std::string format; // For homogeneous buffers, this should be set to format_descriptor::format() 22 | ssize_t ndim = 0; // Number of dimensions 23 | std::vector shape; // Shape of the tensor (1 entry per dimension) 24 | std::vector strides; // Number of entries between adjacent entries (for each per dimension) 25 | 26 | buffer_info() { } 27 | 28 | buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, 29 | detail::any_container shape_in, detail::any_container strides_in) 30 | : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), 31 | shape(std::move(shape_in)), strides(std::move(strides_in)) { 32 | if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) 33 | pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); 34 | for (size_t i = 0; i < (size_t) ndim; ++i) 35 | size *= shape[i]; 36 | } 37 | 38 | template 39 | buffer_info(T *ptr, detail::any_container shape_in, detail::any_container strides_in) 40 | : buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor::format(), static_cast(shape_in->size()), std::move(shape_in), std::move(strides_in)) { } 41 | 42 | buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size) 43 | : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { } 44 | 45 | template 46 | buffer_info(T *ptr, ssize_t size) 47 | : buffer_info(ptr, sizeof(T), format_descriptor::format(), size) { } 48 | 49 | explicit buffer_info(Py_buffer *view, bool ownview = true) 50 | : buffer_info(view->buf, view->itemsize, view->format, view->ndim, 51 | {view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) { 52 | this->view = view; 53 | this->ownview = ownview; 54 | } 55 | 56 | buffer_info(const buffer_info &) = delete; 57 | buffer_info& operator=(const buffer_info &) = delete; 58 | 59 | buffer_info(buffer_info &&other) { 60 | (*this) = std::move(other); 61 | } 62 | 63 | buffer_info& operator=(buffer_info &&rhs) { 64 | ptr = rhs.ptr; 65 | itemsize = rhs.itemsize; 66 | size = rhs.size; 67 | format = std::move(rhs.format); 68 | ndim = rhs.ndim; 69 | shape = std::move(rhs.shape); 70 | strides = std::move(rhs.strides); 71 | std::swap(view, rhs.view); 72 | std::swap(ownview, rhs.ownview); 73 | return *this; 74 | } 75 | 76 | ~buffer_info() { 77 | if (view && ownview) { PyBuffer_Release(view); delete view; } 78 | } 79 | 80 | private: 81 | struct private_ctr_tag { }; 82 | 83 | buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, 84 | detail::any_container &&shape_in, detail::any_container &&strides_in) 85 | : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in)) { } 86 | 87 | Py_buffer *view = nullptr; 88 | bool ownview = false; 89 | }; 90 | 91 | NAMESPACE_BEGIN(detail) 92 | 93 | template struct compare_buffer_info { 94 | static bool compare(const buffer_info& b) { 95 | return b.format == format_descriptor::format() && b.itemsize == (ssize_t) sizeof(T); 96 | } 97 | }; 98 | 99 | template struct compare_buffer_info::value>> { 100 | static bool compare(const buffer_info& b) { 101 | return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor::value || 102 | ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned::value ? "L" : "l")) || 103 | ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned::value ? "N" : "n"))); 104 | } 105 | }; 106 | 107 | NAMESPACE_END(detail) 108 | NAMESPACE_END(PYBIND11_NAMESPACE) 109 | -------------------------------------------------------------------------------- /nms/include/pybind11/chrono.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime 3 | 4 | Copyright (c) 2016 Trent Houliston and 5 | Wenzel Jakob 6 | 7 | All rights reserved. Use of this source code is governed by a 8 | BSD-style license that can be found in the LICENSE file. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "../../../nms/include/pybind11/pybind11.h" 18 | 19 | // Backport the PyDateTime_DELTA functions from Python3.3 if required 20 | #ifndef PyDateTime_DELTA_GET_DAYS 21 | #define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days) 22 | #endif 23 | #ifndef PyDateTime_DELTA_GET_SECONDS 24 | #define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds) 25 | #endif 26 | #ifndef PyDateTime_DELTA_GET_MICROSECONDS 27 | #define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta*)o)->microseconds) 28 | #endif 29 | 30 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 31 | NAMESPACE_BEGIN(detail) 32 | 33 | template class duration_caster { 34 | public: 35 | typedef typename type::rep rep; 36 | typedef typename type::period period; 37 | 38 | typedef std::chrono::duration> days; 39 | 40 | bool load(handle src, bool) { 41 | using namespace std::chrono; 42 | 43 | // Lazy initialise the PyDateTime import 44 | if (!PyDateTimeAPI) { PyDateTime_IMPORT; } 45 | 46 | if (!src) return false; 47 | // If invoked with datetime.delta object 48 | if (PyDelta_Check(src.ptr())) { 49 | value = type(duration_cast>( 50 | days(PyDateTime_DELTA_GET_DAYS(src.ptr())) 51 | + seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) 52 | + microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr())))); 53 | return true; 54 | } 55 | // If invoked with a float we assume it is seconds and convert 56 | else if (PyFloat_Check(src.ptr())) { 57 | value = type(duration_cast>(duration(PyFloat_AsDouble(src.ptr())))); 58 | return true; 59 | } 60 | else return false; 61 | } 62 | 63 | // If this is a duration just return it back 64 | static const std::chrono::duration& get_duration(const std::chrono::duration &src) { 65 | return src; 66 | } 67 | 68 | // If this is a time_point get the time_since_epoch 69 | template static std::chrono::duration get_duration(const std::chrono::time_point> &src) { 70 | return src.time_since_epoch(); 71 | } 72 | 73 | static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) { 74 | using namespace std::chrono; 75 | 76 | // Use overloaded function to get our duration from our source 77 | // Works out if it is a duration or time_point and get the duration 78 | auto d = get_duration(src); 79 | 80 | // Lazy initialise the PyDateTime import 81 | if (!PyDateTimeAPI) { PyDateTime_IMPORT; } 82 | 83 | // Declare these special duration types so the conversions happen with the correct primitive types (int) 84 | using dd_t = duration>; 85 | using ss_t = duration>; 86 | using us_t = duration; 87 | 88 | auto dd = duration_cast(d); 89 | auto subd = d - dd; 90 | auto ss = duration_cast(subd); 91 | auto us = duration_cast(subd - ss); 92 | return PyDelta_FromDSU(dd.count(), ss.count(), us.count()); 93 | } 94 | 95 | PYBIND11_TYPE_CASTER(type, _("datetime.timedelta")); 96 | }; 97 | 98 | // This is for casting times on the system clock into datetime.datetime instances 99 | template class type_caster> { 100 | public: 101 | typedef std::chrono::time_point type; 102 | bool load(handle src, bool) { 103 | using namespace std::chrono; 104 | 105 | // Lazy initialise the PyDateTime import 106 | if (!PyDateTimeAPI) { PyDateTime_IMPORT; } 107 | 108 | if (!src) return false; 109 | if (PyDateTime_Check(src.ptr())) { 110 | std::tm cal; 111 | cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr()); 112 | cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr()); 113 | cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr()); 114 | cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); 115 | cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; 116 | cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; 117 | cal.tm_isdst = -1; 118 | 119 | value = system_clock::from_time_t(std::mktime(&cal)) + microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr())); 120 | return true; 121 | } 122 | else return false; 123 | } 124 | 125 | static handle cast(const std::chrono::time_point &src, return_value_policy /* policy */, handle /* parent */) { 126 | using namespace std::chrono; 127 | 128 | // Lazy initialise the PyDateTime import 129 | if (!PyDateTimeAPI) { PyDateTime_IMPORT; } 130 | 131 | std::time_t tt = system_clock::to_time_t(src); 132 | // this function uses static memory so it's best to copy it out asap just in case 133 | // otherwise other code that is using localtime may break this (not just python code) 134 | std::tm localtime = *std::localtime(&tt); 135 | 136 | // Declare these special duration types so the conversions happen with the correct primitive types (int) 137 | using us_t = duration; 138 | 139 | return PyDateTime_FromDateAndTime(localtime.tm_year + 1900, 140 | localtime.tm_mon + 1, 141 | localtime.tm_mday, 142 | localtime.tm_hour, 143 | localtime.tm_min, 144 | localtime.tm_sec, 145 | (duration_cast(src.time_since_epoch() % seconds(1))).count()); 146 | } 147 | PYBIND11_TYPE_CASTER(type, _("datetime.datetime")); 148 | }; 149 | 150 | // Other clocks that are not the system clock are not measured as datetime.datetime objects 151 | // since they are not measured on calendar time. So instead we just make them timedeltas 152 | // Or if they have passed us a time as a float we convert that 153 | template class type_caster> 154 | : public duration_caster> { 155 | }; 156 | 157 | template class type_caster> 158 | : public duration_caster> { 159 | }; 160 | 161 | NAMESPACE_END(detail) 162 | NAMESPACE_END(PYBIND11_NAMESPACE) 163 | -------------------------------------------------------------------------------- /nms/include/pybind11/common.h: -------------------------------------------------------------------------------- 1 | #include "../../../nms/include/pybind11/detail/common.h" 2 | #warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'." 3 | -------------------------------------------------------------------------------- /nms/include/pybind11/complex.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/complex.h: Complex number support 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | #include "../../../nms/include/pybind11/pybind11.h" 14 | 15 | /// glibc defines I as a macro which breaks things, e.g., boost template names 16 | #ifdef I 17 | # undef I 18 | #endif 19 | 20 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 21 | 22 | template struct format_descriptor, detail::enable_if_t::value>> { 23 | static constexpr const char c = format_descriptor::c; 24 | static constexpr const char value[3] = { 'Z', c, '\0' }; 25 | static std::string format() { return std::string(value); } 26 | }; 27 | 28 | #ifndef PYBIND11_CPP17 29 | 30 | template constexpr const char format_descriptor< 31 | std::complex, detail::enable_if_t::value>>::value[3]; 32 | 33 | #endif 34 | 35 | NAMESPACE_BEGIN(detail) 36 | 37 | template struct is_fmt_numeric, detail::enable_if_t::value>> { 38 | static constexpr bool value = true; 39 | static constexpr int index = is_fmt_numeric::index + 3; 40 | }; 41 | 42 | template class type_caster> { 43 | public: 44 | bool load(handle src, bool convert) { 45 | if (!src) 46 | return false; 47 | if (!convert && !PyComplex_Check(src.ptr())) 48 | return false; 49 | Py_complex result = PyComplex_AsCComplex(src.ptr()); 50 | if (result.real == -1.0 && PyErr_Occurred()) { 51 | PyErr_Clear(); 52 | return false; 53 | } 54 | value = std::complex((T) result.real, (T) result.imag); 55 | return true; 56 | } 57 | 58 | static handle cast(const std::complex &src, return_value_policy /* policy */, handle /* parent */) { 59 | return PyComplex_FromDoubles((double) src.real(), (double) src.imag()); 60 | } 61 | 62 | PYBIND11_TYPE_CASTER(std::complex, _("complex")); 63 | }; 64 | NAMESPACE_END(detail) 65 | NAMESPACE_END(PYBIND11_NAMESPACE) 66 | -------------------------------------------------------------------------------- /nms/include/pybind11/detail/descr.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "../../../../nms/include/pybind11/detail/common.h" 13 | 14 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 15 | NAMESPACE_BEGIN(detail) 16 | 17 | #if !defined(_MSC_VER) 18 | # define PYBIND11_DESCR_CONSTEXPR static constexpr 19 | #else 20 | # define PYBIND11_DESCR_CONSTEXPR const 21 | #endif 22 | 23 | /* Concatenate type signatures at compile time */ 24 | template 25 | struct descr { 26 | char text[N + 1]; 27 | 28 | constexpr descr() : text{'\0'} { } 29 | constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence()) { } 30 | 31 | template 32 | constexpr descr(char const (&s)[N+1], index_sequence) : text{s[Is]..., '\0'} { } 33 | 34 | template 35 | constexpr descr(char c, Chars... cs) : text{c, static_cast(cs)..., '\0'} { } 36 | 37 | static constexpr std::array types() { 38 | return {{&typeid(Ts)..., nullptr}}; 39 | } 40 | }; 41 | 42 | template 43 | constexpr descr plus_impl(const descr &a, const descr &b, 44 | index_sequence, index_sequence) { 45 | return {a.text[Is1]..., b.text[Is2]...}; 46 | } 47 | 48 | template 49 | constexpr descr operator+(const descr &a, const descr &b) { 50 | return plus_impl(a, b, make_index_sequence(), make_index_sequence()); 51 | } 52 | 53 | template 54 | constexpr descr _(char const(&text)[N]) { return descr(text); } 55 | constexpr descr<0> _(char const(&)[1]) { return {}; } 56 | 57 | template struct int_to_str : int_to_str { }; 58 | template struct int_to_str<0, Digits...> { 59 | static constexpr auto digits = descr(('0' + Digits)...); 60 | }; 61 | 62 | // Ternary description (like std::conditional) 63 | template 64 | constexpr enable_if_t> _(char const(&text1)[N1], char const(&)[N2]) { 65 | return _(text1); 66 | } 67 | template 68 | constexpr enable_if_t> _(char const(&)[N1], char const(&text2)[N2]) { 69 | return _(text2); 70 | } 71 | 72 | template 73 | constexpr enable_if_t _(const T1 &d, const T2 &) { return d; } 74 | template 75 | constexpr enable_if_t _(const T1 &, const T2 &d) { return d; } 76 | 77 | template auto constexpr _() -> decltype(int_to_str::digits) { 78 | return int_to_str::digits; 79 | } 80 | 81 | template constexpr descr<1, Type> _() { return {'%'}; } 82 | 83 | constexpr descr<0> concat() { return {}; } 84 | 85 | template 86 | constexpr descr concat(const descr &descr) { return descr; } 87 | 88 | template 89 | constexpr auto concat(const descr &d, const Args &...args) 90 | -> decltype(std::declval>() + concat(args...)) { 91 | return d + _(", ") + concat(args...); 92 | } 93 | 94 | template 95 | constexpr descr type_descr(const descr &descr) { 96 | return _("{") + descr + _("}"); 97 | } 98 | 99 | NAMESPACE_END(detail) 100 | NAMESPACE_END(PYBIND11_NAMESPACE) 101 | -------------------------------------------------------------------------------- /nms/include/pybind11/detail/init.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/detail/init.h: init factory function implementation and support code. 3 | 4 | Copyright (c) 2017 Jason Rhinelander 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "../../../../nms/include/pybind11/detail/class.h" 13 | 14 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 15 | NAMESPACE_BEGIN(detail) 16 | 17 | template <> 18 | class type_caster { 19 | public: 20 | bool load(handle h, bool) { 21 | value = reinterpret_cast(h.ptr()); 22 | return true; 23 | } 24 | 25 | template using cast_op_type = value_and_holder &; 26 | operator value_and_holder &() { return *value; } 27 | static constexpr auto name = _(); 28 | 29 | private: 30 | value_and_holder *value = nullptr; 31 | }; 32 | 33 | NAMESPACE_BEGIN(initimpl) 34 | 35 | inline void no_nullptr(void *ptr) { 36 | if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr"); 37 | } 38 | 39 | // Implementing functions for all forms of py::init<...> and py::init(...) 40 | template using Cpp = typename Class::type; 41 | template using Alias = typename Class::type_alias; 42 | template using Holder = typename Class::holder_type; 43 | 44 | template using is_alias_constructible = std::is_constructible, Cpp &&>; 45 | 46 | // Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance. 47 | template = 0> 48 | bool is_alias(Cpp *ptr) { 49 | return dynamic_cast *>(ptr) != nullptr; 50 | } 51 | // Failing fallback version of the above for a no-alias class (always returns false) 52 | template 53 | constexpr bool is_alias(void *) { return false; } 54 | 55 | // Constructs and returns a new object; if the given arguments don't map to a constructor, we fall 56 | // back to brace aggregate initiailization so that for aggregate initialization can be used with 57 | // py::init, e.g. `py::init` to initialize a `struct T { int a; int b; }`. For 58 | // non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually 59 | // works, but will not do the expected thing when `T` has an `initializer_list` constructor). 60 | template ::value, int> = 0> 61 | inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward(args)...); } 62 | template ::value, int> = 0> 63 | inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward(args)...}; } 64 | 65 | // Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with 66 | // an alias to provide only a single Cpp factory function as long as the Alias can be 67 | // constructed from an rvalue reference of the base Cpp type. This means that Alias classes 68 | // can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to 69 | // inherit all the base class constructors. 70 | template 71 | void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/, 72 | value_and_holder &v_h, Cpp &&base) { 73 | v_h.value_ptr() = new Alias(std::move(base)); 74 | } 75 | template 76 | [[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/, 77 | value_and_holder &, Cpp &&) { 78 | throw type_error("pybind11::init(): unable to convert returned instance to required " 79 | "alias class: no `Alias(Class &&)` constructor available"); 80 | } 81 | 82 | // Error-generating fallback for factories that don't match one of the below construction 83 | // mechanisms. 84 | template 85 | void construct(...) { 86 | static_assert(!std::is_same::value /* always false */, 87 | "pybind11::init(): init function must return a compatible pointer, " 88 | "holder, or value"); 89 | } 90 | 91 | // Pointer return v1: the factory function returns a class pointer for a registered class. 92 | // If we don't need an alias (because this class doesn't have one, or because the final type is 93 | // inherited on the Python side) we can simply take over ownership. Otherwise we need to try to 94 | // construct an Alias from the returned base instance. 95 | template 96 | void construct(value_and_holder &v_h, Cpp *ptr, bool need_alias) { 97 | no_nullptr(ptr); 98 | if (Class::has_alias && need_alias && !is_alias(ptr)) { 99 | // We're going to try to construct an alias by moving the cpp type. Whether or not 100 | // that succeeds, we still need to destroy the original cpp pointer (either the 101 | // moved away leftover, if the alias construction works, or the value itself if we 102 | // throw an error), but we can't just call `delete ptr`: it might have a special 103 | // deleter, or might be shared_from_this. So we construct a holder around it as if 104 | // it was a normal instance, then steal the holder away into a local variable; thus 105 | // the holder and destruction happens when we leave the C++ scope, and the holder 106 | // class gets to handle the destruction however it likes. 107 | v_h.value_ptr() = ptr; 108 | v_h.set_instance_registered(true); // To prevent init_instance from registering it 109 | v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder 110 | Holder temp_holder(std::move(v_h.holder>())); // Steal the holder 111 | v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null 112 | v_h.set_instance_registered(false); 113 | 114 | construct_alias_from_cpp(is_alias_constructible{}, v_h, std::move(*ptr)); 115 | } else { 116 | // Otherwise the type isn't inherited, so we don't need an Alias 117 | v_h.value_ptr() = ptr; 118 | } 119 | } 120 | 121 | // Pointer return v2: a factory that always returns an alias instance ptr. We simply take over 122 | // ownership of the pointer. 123 | template = 0> 124 | void construct(value_and_holder &v_h, Alias *alias_ptr, bool) { 125 | no_nullptr(alias_ptr); 126 | v_h.value_ptr() = static_cast *>(alias_ptr); 127 | } 128 | 129 | // Holder return: copy its pointer, and move or copy the returned holder into the new instance's 130 | // holder. This also handles types like std::shared_ptr and std::unique_ptr where T is a 131 | // derived type (through those holder's implicit conversion from derived class holder constructors). 132 | template 133 | void construct(value_and_holder &v_h, Holder holder, bool need_alias) { 134 | auto *ptr = holder_helper>::get(holder); 135 | // If we need an alias, check that the held pointer is actually an alias instance 136 | if (Class::has_alias && need_alias && !is_alias(ptr)) 137 | throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance " 138 | "is not an alias instance"); 139 | 140 | v_h.value_ptr() = ptr; 141 | v_h.type->init_instance(v_h.inst, &holder); 142 | } 143 | 144 | // return-by-value version 1: returning a cpp class by value. If the class has an alias and an 145 | // alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct 146 | // the alias from the base when needed (i.e. because of Python-side inheritance). When we don't 147 | // need it, we simply move-construct the cpp value into a new instance. 148 | template 149 | void construct(value_and_holder &v_h, Cpp &&result, bool need_alias) { 150 | static_assert(std::is_move_constructible>::value, 151 | "pybind11::init() return-by-value factory function requires a movable class"); 152 | if (Class::has_alias && need_alias) 153 | construct_alias_from_cpp(is_alias_constructible{}, v_h, std::move(result)); 154 | else 155 | v_h.value_ptr() = new Cpp(std::move(result)); 156 | } 157 | 158 | // return-by-value version 2: returning a value of the alias type itself. We move-construct an 159 | // Alias instance (even if no the python-side inheritance is involved). The is intended for 160 | // cases where Alias initialization is always desired. 161 | template 162 | void construct(value_and_holder &v_h, Alias &&result, bool) { 163 | static_assert(std::is_move_constructible>::value, 164 | "pybind11::init() return-by-alias-value factory function requires a movable alias class"); 165 | v_h.value_ptr() = new Alias(std::move(result)); 166 | } 167 | 168 | // Implementing class for py::init<...>() 169 | template 170 | struct constructor { 171 | template = 0> 172 | static void execute(Class &cl, const Extra&... extra) { 173 | cl.def("__init__", [](value_and_holder &v_h, Args... args) { 174 | v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); 175 | }, is_new_style_constructor(), extra...); 176 | } 177 | 178 | template , Args...>::value, int> = 0> 181 | static void execute(Class &cl, const Extra&... extra) { 182 | cl.def("__init__", [](value_and_holder &v_h, Args... args) { 183 | if (Py_TYPE(v_h.inst) == v_h.type->type) 184 | v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); 185 | else 186 | v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); 187 | }, is_new_style_constructor(), extra...); 188 | } 189 | 190 | template , Args...>::value, int> = 0> 193 | static void execute(Class &cl, const Extra&... extra) { 194 | cl.def("__init__", [](value_and_holder &v_h, Args... args) { 195 | v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); 196 | }, is_new_style_constructor(), extra...); 197 | } 198 | }; 199 | 200 | // Implementing class for py::init_alias<...>() 201 | template struct alias_constructor { 202 | template , Args...>::value, int> = 0> 204 | static void execute(Class &cl, const Extra&... extra) { 205 | cl.def("__init__", [](value_and_holder &v_h, Args... args) { 206 | v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); 207 | }, is_new_style_constructor(), extra...); 208 | } 209 | }; 210 | 211 | // Implementation class for py::init(Func) and py::init(Func, AliasFunc) 212 | template , typename = function_signature_t> 214 | struct factory; 215 | 216 | // Specialization for py::init(Func) 217 | template 218 | struct factory { 219 | remove_reference_t class_factory; 220 | 221 | factory(Func &&f) : class_factory(std::forward(f)) { } 222 | 223 | // The given class either has no alias or has no separate alias factory; 224 | // this always constructs the class itself. If the class is registered with an alias 225 | // type and an alias instance is needed (i.e. because the final type is a Python class 226 | // inheriting from the C++ type) the returned value needs to either already be an alias 227 | // instance, or the alias needs to be constructible from a `Class &&` argument. 228 | template 229 | void execute(Class &cl, const Extra &...extra) && { 230 | #if defined(PYBIND11_CPP14) 231 | cl.def("__init__", [func = std::move(class_factory)] 232 | #else 233 | auto &func = class_factory; 234 | cl.def("__init__", [func] 235 | #endif 236 | (value_and_holder &v_h, Args... args) { 237 | construct(v_h, func(std::forward(args)...), 238 | Py_TYPE(v_h.inst) != v_h.type->type); 239 | }, is_new_style_constructor(), extra...); 240 | } 241 | }; 242 | 243 | // Specialization for py::init(Func, AliasFunc) 244 | template 246 | struct factory { 247 | static_assert(sizeof...(CArgs) == sizeof...(AArgs), 248 | "pybind11::init(class_factory, alias_factory): class and alias factories " 249 | "must have identical argument signatures"); 250 | static_assert(all_of...>::value, 251 | "pybind11::init(class_factory, alias_factory): class and alias factories " 252 | "must have identical argument signatures"); 253 | 254 | remove_reference_t class_factory; 255 | remove_reference_t alias_factory; 256 | 257 | factory(CFunc &&c, AFunc &&a) 258 | : class_factory(std::forward(c)), alias_factory(std::forward(a)) { } 259 | 260 | // The class factory is called when the `self` type passed to `__init__` is the direct 261 | // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype. 262 | template 263 | void execute(Class &cl, const Extra&... extra) && { 264 | static_assert(Class::has_alias, "The two-argument version of `py::init()` can " 265 | "only be used if the class has an alias"); 266 | #if defined(PYBIND11_CPP14) 267 | cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)] 268 | #else 269 | auto &class_func = class_factory; 270 | auto &alias_func = alias_factory; 271 | cl.def("__init__", [class_func, alias_func] 272 | #endif 273 | (value_and_holder &v_h, CArgs... args) { 274 | if (Py_TYPE(v_h.inst) == v_h.type->type) 275 | // If the instance type equals the registered type we don't have inheritance, so 276 | // don't need the alias and can construct using the class function: 277 | construct(v_h, class_func(std::forward(args)...), false); 278 | else 279 | construct(v_h, alias_func(std::forward(args)...), true); 280 | }, is_new_style_constructor(), extra...); 281 | } 282 | }; 283 | 284 | /// Set just the C++ state. Same as `__init__`. 285 | template 286 | void setstate(value_and_holder &v_h, T &&result, bool need_alias) { 287 | construct(v_h, std::forward(result), need_alias); 288 | } 289 | 290 | /// Set both the C++ and Python states 291 | template ::value, int> = 0> 293 | void setstate(value_and_holder &v_h, std::pair &&result, bool need_alias) { 294 | construct(v_h, std::move(result.first), need_alias); 295 | setattr((PyObject *) v_h.inst, "__dict__", result.second); 296 | } 297 | 298 | /// Implementation for py::pickle(GetState, SetState) 299 | template , typename = function_signature_t> 301 | struct pickle_factory; 302 | 303 | template 305 | struct pickle_factory { 306 | static_assert(std::is_same, intrinsic_t>::value, 307 | "The type returned by `__getstate__` must be the same " 308 | "as the argument accepted by `__setstate__`"); 309 | 310 | remove_reference_t get; 311 | remove_reference_t set; 312 | 313 | pickle_factory(Get get, Set set) 314 | : get(std::forward(get)), set(std::forward(set)) { } 315 | 316 | template 317 | void execute(Class &cl, const Extra &...extra) && { 318 | cl.def("__getstate__", std::move(get)); 319 | 320 | #if defined(PYBIND11_CPP14) 321 | cl.def("__setstate__", [func = std::move(set)] 322 | #else 323 | auto &func = set; 324 | cl.def("__setstate__", [func] 325 | #endif 326 | (value_and_holder &v_h, ArgState state) { 327 | setstate(v_h, func(std::forward(state)), 328 | Py_TYPE(v_h.inst) != v_h.type->type); 329 | }, is_new_style_constructor(), extra...); 330 | } 331 | }; 332 | 333 | NAMESPACE_END(initimpl) 334 | NAMESPACE_END(detail) 335 | NAMESPACE_END(pybind11) 336 | -------------------------------------------------------------------------------- /nms/include/pybind11/detail/internals.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/detail/internals.h: Internal data structure and related functions 3 | 4 | Copyright (c) 2017 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "../pytypes.h" 13 | 14 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 15 | NAMESPACE_BEGIN(detail) 16 | // Forward declarations 17 | inline PyTypeObject *make_static_property_type(); 18 | inline PyTypeObject *make_default_metaclass(); 19 | inline PyObject *make_object_base_type(PyTypeObject *metaclass); 20 | 21 | // Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly 22 | // other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module 23 | // even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under 24 | // libstdc++, this doesn't happen: equality and the type_index hash are based on the type name, 25 | // which works. If not under a known-good stl, provide our own name-based hash and equality 26 | // functions that use the type name. 27 | #if defined(__GLIBCXX__) 28 | inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; } 29 | using type_hash = std::hash; 30 | using type_equal_to = std::equal_to; 31 | #else 32 | inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { 33 | return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; 34 | } 35 | 36 | struct type_hash { 37 | size_t operator()(const std::type_index &t) const { 38 | size_t hash = 5381; 39 | const char *ptr = t.name(); 40 | while (auto c = static_cast(*ptr++)) 41 | hash = (hash * 33) ^ c; 42 | return hash; 43 | } 44 | }; 45 | 46 | struct type_equal_to { 47 | bool operator()(const std::type_index &lhs, const std::type_index &rhs) const { 48 | return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; 49 | } 50 | }; 51 | #endif 52 | 53 | template 54 | using type_map = std::unordered_map; 55 | 56 | struct overload_hash { 57 | inline size_t operator()(const std::pair& v) const { 58 | size_t value = std::hash()(v.first); 59 | value ^= std::hash()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2); 60 | return value; 61 | } 62 | }; 63 | 64 | /// Internal data structure used to track registered instances and types. 65 | /// Whenever binary incompatible changes are made to this structure, 66 | /// `PYBIND11_INTERNALS_VERSION` must be incremented. 67 | struct internals { 68 | type_map registered_types_cpp; // std::type_index -> pybind11's type information 69 | std::unordered_map> registered_types_py; // PyTypeObject* -> base type_info(s) 70 | std::unordered_multimap registered_instances; // void * -> instance* 71 | std::unordered_set, overload_hash> inactive_overload_cache; 72 | type_map> direct_conversions; 73 | std::unordered_map> patients; 74 | std::forward_list registered_exception_translators; 75 | std::unordered_map shared_data; // Custom data to be shared across extensions 76 | std::vector loader_patient_stack; // Used by `loader_life_support` 77 | std::forward_list static_strings; // Stores the std::strings backing detail::c_str() 78 | PyTypeObject *static_property_type; 79 | PyTypeObject *default_metaclass; 80 | PyObject *instance_base; 81 | #if defined(WITH_THREAD) 82 | decltype(PyThread_create_key()) tstate = 0; // Usually an int but a long on Cygwin64 with Python 3.x 83 | PyInterpreterState *istate = nullptr; 84 | #endif 85 | }; 86 | 87 | /// Additional type information which does not fit into the PyTypeObject. 88 | /// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`. 89 | struct type_info { 90 | PyTypeObject *type; 91 | const std::type_info *cpptype; 92 | size_t type_size, holder_size_in_ptrs; 93 | void *(*operator_new)(size_t); 94 | void (*init_instance)(instance *, const void *); 95 | void (*dealloc)(value_and_holder &v_h); 96 | std::vector implicit_conversions; 97 | std::vector> implicit_casts; 98 | std::vector *direct_conversions; 99 | buffer_info *(*get_buffer)(PyObject *, void *) = nullptr; 100 | void *get_buffer_data = nullptr; 101 | void *(*module_local_load)(PyObject *, const type_info *) = nullptr; 102 | /* A simple type never occurs as a (direct or indirect) parent 103 | * of a class that makes use of multiple inheritance */ 104 | bool simple_type : 1; 105 | /* True if there is no multiple inheritance in this type's inheritance tree */ 106 | bool simple_ancestors : 1; 107 | /* for base vs derived holder_type checks */ 108 | bool default_holder : 1; 109 | /* true if this is a type registered with py::module_local */ 110 | bool module_local : 1; 111 | }; 112 | 113 | /// Tracks the `internals` and `type_info` ABI version independent of the main library version 114 | #define PYBIND11_INTERNALS_VERSION 1 115 | 116 | #if defined(WITH_THREAD) 117 | # define PYBIND11_INTERNALS_KIND "" 118 | #else 119 | # define PYBIND11_INTERNALS_KIND "_without_thread" 120 | #endif 121 | 122 | #define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \ 123 | PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__" 124 | 125 | #define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \ 126 | PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__" 127 | 128 | /// Each module locally stores a pointer to the `internals` data. The data 129 | /// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. 130 | inline internals **&get_internals_pp() { 131 | static internals **internals_pp = nullptr; 132 | return internals_pp; 133 | } 134 | 135 | /// Return a reference to the current `internals` data 136 | PYBIND11_NOINLINE inline internals &get_internals() { 137 | auto **&internals_pp = get_internals_pp(); 138 | if (internals_pp && *internals_pp) 139 | return **internals_pp; 140 | 141 | constexpr auto *id = PYBIND11_INTERNALS_ID; 142 | auto builtins = handle(PyEval_GetBuiltins()); 143 | if (builtins.contains(id) && isinstance(builtins[id])) { 144 | internals_pp = static_cast(capsule(builtins[id])); 145 | 146 | // We loaded builtins through python's builtins, which means that our `error_already_set` 147 | // and `builtin_exception` may be different local classes than the ones set up in the 148 | // initial exception translator, below, so add another for our local exception classes. 149 | // 150 | // libstdc++ doesn't require this (types there are identified only by name) 151 | #if !defined(__GLIBCXX__) 152 | (*internals_pp)->registered_exception_translators.push_front( 153 | [](std::exception_ptr p) -> void { 154 | try { 155 | if (p) std::rethrow_exception(p); 156 | } catch (error_already_set &e) { e.restore(); return; 157 | } catch (const builtin_exception &e) { e.set_error(); return; 158 | } 159 | } 160 | ); 161 | #endif 162 | } else { 163 | if (!internals_pp) internals_pp = new internals*(); 164 | auto *&internals_ptr = *internals_pp; 165 | internals_ptr = new internals(); 166 | #if defined(WITH_THREAD) 167 | PyEval_InitThreads(); 168 | PyThreadState *tstate = PyThreadState_Get(); 169 | internals_ptr->tstate = PyThread_create_key(); 170 | PyThread_set_key_value(internals_ptr->tstate, tstate); 171 | internals_ptr->istate = tstate->interp; 172 | #endif 173 | builtins[id] = capsule(internals_pp); 174 | internals_ptr->registered_exception_translators.push_front( 175 | [](std::exception_ptr p) -> void { 176 | try { 177 | if (p) std::rethrow_exception(p); 178 | } catch (error_already_set &e) { e.restore(); return; 179 | } catch (const builtin_exception &e) { e.set_error(); return; 180 | } catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return; 181 | } catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; 182 | } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; 183 | } catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; 184 | } catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return; 185 | } catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; 186 | } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return; 187 | } catch (...) { 188 | PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!"); 189 | return; 190 | } 191 | } 192 | ); 193 | internals_ptr->static_property_type = make_static_property_type(); 194 | internals_ptr->default_metaclass = make_default_metaclass(); 195 | internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass); 196 | } 197 | return **internals_pp; 198 | } 199 | 200 | /// Works like `internals.registered_types_cpp`, but for module-local registered types: 201 | inline type_map ®istered_local_types_cpp() { 202 | static type_map locals{}; 203 | return locals; 204 | } 205 | 206 | /// Constructs a std::string with the given arguments, stores it in `internals`, and returns its 207 | /// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only 208 | /// cleared when the program exits or after interpreter shutdown (when embedding), and so are 209 | /// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name). 210 | template 211 | const char *c_str(Args &&...args) { 212 | auto &strings = get_internals().static_strings; 213 | strings.emplace_front(std::forward(args)...); 214 | return strings.front().c_str(); 215 | } 216 | 217 | NAMESPACE_END(detail) 218 | 219 | /// Returns a named pointer that is shared among all extension modules (using the same 220 | /// pybind11 version) running in the current interpreter. Names starting with underscores 221 | /// are reserved for internal usage. Returns `nullptr` if no matching entry was found. 222 | inline PYBIND11_NOINLINE void *get_shared_data(const std::string &name) { 223 | auto &internals = detail::get_internals(); 224 | auto it = internals.shared_data.find(name); 225 | return it != internals.shared_data.end() ? it->second : nullptr; 226 | } 227 | 228 | /// Set the shared data that can be later recovered by `get_shared_data()`. 229 | inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) { 230 | detail::get_internals().shared_data[name] = data; 231 | return data; 232 | } 233 | 234 | /// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if 235 | /// such entry exists. Otherwise, a new object of default-constructible type `T` is 236 | /// added to the shared data under the given name and a reference to it is returned. 237 | template 238 | T &get_or_create_shared_data(const std::string &name) { 239 | auto &internals = detail::get_internals(); 240 | auto it = internals.shared_data.find(name); 241 | T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr); 242 | if (!ptr) { 243 | ptr = new T(); 244 | internals.shared_data[name] = ptr; 245 | } 246 | return *ptr; 247 | } 248 | 249 | NAMESPACE_END(PYBIND11_NAMESPACE) 250 | -------------------------------------------------------------------------------- /nms/include/pybind11/detail/typeid.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/detail/typeid.h: Compiler-independent access to type identifiers 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | #include 14 | 15 | #if defined(__GNUG__) 16 | #include 17 | #endif 18 | 19 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 20 | NAMESPACE_BEGIN(detail) 21 | /// Erase all occurrences of a substring 22 | inline void erase_all(std::string &string, const std::string &search) { 23 | for (size_t pos = 0;;) { 24 | pos = string.find(search, pos); 25 | if (pos == std::string::npos) break; 26 | string.erase(pos, search.length()); 27 | } 28 | } 29 | 30 | PYBIND11_NOINLINE inline void clean_type_id(std::string &name) { 31 | #if defined(__GNUG__) 32 | int status = 0; 33 | std::unique_ptr res { 34 | abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free }; 35 | if (status == 0) 36 | name = res.get(); 37 | #else 38 | detail::erase_all(name, "class "); 39 | detail::erase_all(name, "struct "); 40 | detail::erase_all(name, "enum "); 41 | #endif 42 | detail::erase_all(name, "pybind11::"); 43 | } 44 | NAMESPACE_END(detail) 45 | 46 | /// Return a string representation of a C++ type 47 | template static std::string type_id() { 48 | std::string name(typeid(T).name()); 49 | detail::clean_type_id(name); 50 | return name; 51 | } 52 | 53 | NAMESPACE_END(PYBIND11_NAMESPACE) 54 | -------------------------------------------------------------------------------- /nms/include/pybind11/embed.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/embed.h: Support for embedding the interpreter 3 | 4 | Copyright (c) 2017 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "../../../nms/include/pybind11/eval.h" 13 | #include "../../../nms/include/pybind11/pybind11.h" 14 | 15 | #if defined(PYPY_VERSION) 16 | # error Embedding the interpreter is not supported with PyPy 17 | #endif 18 | 19 | #if PY_MAJOR_VERSION >= 3 20 | # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ 21 | extern "C" PyObject *pybind11_init_impl_##name() { \ 22 | return pybind11_init_wrapper_##name(); \ 23 | } 24 | #else 25 | # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ 26 | extern "C" void pybind11_init_impl_##name() { \ 27 | pybind11_init_wrapper_##name(); \ 28 | } 29 | #endif 30 | 31 | /** \rst 32 | Add a new module to the table of builtins for the interpreter. Must be 33 | defined in global scope. The first macro parameter is the name of the 34 | module (without quotes). The second parameter is the variable which will 35 | be used as the interface to add functions and classes to the module. 36 | 37 | .. code-block:: cpp 38 | 39 | PYBIND11_EMBEDDED_MODULE(example, m) { 40 | // ... initialize functions and classes here 41 | m.def("foo", []() { 42 | return "Hello, World!"; 43 | }); 44 | } 45 | \endrst */ 46 | #define PYBIND11_EMBEDDED_MODULE(name, variable) \ 47 | static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ 48 | static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \ 49 | auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ 50 | try { \ 51 | PYBIND11_CONCAT(pybind11_init_, name)(m); \ 52 | return m.ptr(); \ 53 | } catch (pybind11::error_already_set &e) { \ 54 | PyErr_SetString(PyExc_ImportError, e.what()); \ 55 | return nullptr; \ 56 | } catch (const std::exception &e) { \ 57 | PyErr_SetString(PyExc_ImportError, e.what()); \ 58 | return nullptr; \ 59 | } \ 60 | } \ 61 | PYBIND11_EMBEDDED_MODULE_IMPL(name) \ 62 | pybind11::detail::embedded_module name(PYBIND11_TOSTRING(name), \ 63 | PYBIND11_CONCAT(pybind11_init_impl_, name)); \ 64 | void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable) 65 | 66 | 67 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 68 | NAMESPACE_BEGIN(detail) 69 | 70 | /// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks. 71 | struct embedded_module { 72 | #if PY_MAJOR_VERSION >= 3 73 | using init_t = PyObject *(*)(); 74 | #else 75 | using init_t = void (*)(); 76 | #endif 77 | embedded_module(const char *name, init_t init) { 78 | if (Py_IsInitialized()) 79 | pybind11_fail("Can't add new modules after the interpreter has been initialized"); 80 | 81 | auto result = PyImport_AppendInittab(name, init); 82 | if (result == -1) 83 | pybind11_fail("Insufficient memory to add a new module"); 84 | } 85 | }; 86 | 87 | NAMESPACE_END(detail) 88 | 89 | /** \rst 90 | Initialize the Python interpreter. No other pybind11 or CPython API functions can be 91 | called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The 92 | optional parameter can be used to skip the registration of signal handlers (see the 93 | Python documentation for details). Calling this function again after the interpreter 94 | has already been initialized is a fatal error. 95 | \endrst */ 96 | inline void initialize_interpreter(bool init_signal_handlers = true) { 97 | if (Py_IsInitialized()) 98 | pybind11_fail("The interpreter is already running"); 99 | 100 | Py_InitializeEx(init_signal_handlers ? 1 : 0); 101 | 102 | // Make .py files in the working directory available by default 103 | module::import("sys").attr("path").cast().append("."); 104 | } 105 | 106 | /** \rst 107 | Shut down the Python interpreter. No pybind11 or CPython API functions can be called 108 | after this. In addition, pybind11 objects must not outlive the interpreter: 109 | 110 | .. code-block:: cpp 111 | 112 | { // BAD 113 | py::initialize_interpreter(); 114 | auto hello = py::str("Hello, World!"); 115 | py::finalize_interpreter(); 116 | } // <-- BOOM, hello's destructor is called after interpreter shutdown 117 | 118 | { // GOOD 119 | py::initialize_interpreter(); 120 | { // scoped 121 | auto hello = py::str("Hello, World!"); 122 | } // <-- OK, hello is cleaned up properly 123 | py::finalize_interpreter(); 124 | } 125 | 126 | { // BETTER 127 | py::scoped_interpreter guard{}; 128 | auto hello = py::str("Hello, World!"); 129 | } 130 | 131 | .. warning:: 132 | 133 | The interpreter can be restarted by calling `initialize_interpreter` again. 134 | Modules created using pybind11 can be safely re-initialized. However, Python 135 | itself cannot completely unload binary extension modules and there are several 136 | caveats with regard to interpreter restarting. All the details can be found 137 | in the CPython documentation. In short, not all interpreter memory may be 138 | freed, either due to reference cycles or user-created global data. 139 | 140 | \endrst */ 141 | inline void finalize_interpreter() { 142 | handle builtins(PyEval_GetBuiltins()); 143 | const char *id = PYBIND11_INTERNALS_ID; 144 | 145 | // Get the internals pointer (without creating it if it doesn't exist). It's possible for the 146 | // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()` 147 | // during destruction), so we get the pointer-pointer here and check it after Py_Finalize(). 148 | detail::internals **internals_ptr_ptr = detail::get_internals_pp(); 149 | // It could also be stashed in builtins, so look there too: 150 | if (builtins.contains(id) && isinstance(builtins[id])) 151 | internals_ptr_ptr = capsule(builtins[id]); 152 | 153 | Py_Finalize(); 154 | 155 | if (internals_ptr_ptr) { 156 | delete *internals_ptr_ptr; 157 | *internals_ptr_ptr = nullptr; 158 | } 159 | } 160 | 161 | /** \rst 162 | Scope guard version of `initialize_interpreter` and `finalize_interpreter`. 163 | This a move-only guard and only a single instance can exist. 164 | 165 | .. code-block:: cpp 166 | 167 | #include 168 | 169 | int main() { 170 | py::scoped_interpreter guard{}; 171 | py::print(Hello, World!); 172 | } // <-- interpreter shutdown 173 | \endrst */ 174 | class scoped_interpreter { 175 | public: 176 | scoped_interpreter(bool init_signal_handlers = true) { 177 | initialize_interpreter(init_signal_handlers); 178 | } 179 | 180 | scoped_interpreter(const scoped_interpreter &) = delete; 181 | scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; } 182 | scoped_interpreter &operator=(const scoped_interpreter &) = delete; 183 | scoped_interpreter &operator=(scoped_interpreter &&) = delete; 184 | 185 | ~scoped_interpreter() { 186 | if (is_valid) 187 | finalize_interpreter(); 188 | } 189 | 190 | private: 191 | bool is_valid = true; 192 | }; 193 | 194 | NAMESPACE_END(PYBIND11_NAMESPACE) 195 | -------------------------------------------------------------------------------- /nms/include/pybind11/eval.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/exec.h: Support for evaluating Python expressions and statements 3 | from strings and files 4 | 5 | Copyright (c) 2016 Klemens Morgenstern and 6 | Wenzel Jakob 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE file. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "../../../nms/include/pybind11/pybind11.h" 15 | 16 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 17 | 18 | enum eval_mode { 19 | /// Evaluate a string containing an isolated expression 20 | eval_expr, 21 | 22 | /// Evaluate a string containing a single statement. Returns \c none 23 | eval_single_statement, 24 | 25 | /// Evaluate a string containing a sequence of statement. Returns \c none 26 | eval_statements 27 | }; 28 | 29 | template 30 | object eval(str expr, object global = globals(), object local = object()) { 31 | if (!local) 32 | local = global; 33 | 34 | /* PyRun_String does not accept a PyObject / encoding specifier, 35 | this seems to be the only alternative */ 36 | std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr; 37 | 38 | int start; 39 | switch (mode) { 40 | case eval_expr: start = Py_eval_input; break; 41 | case eval_single_statement: start = Py_single_input; break; 42 | case eval_statements: start = Py_file_input; break; 43 | default: pybind11_fail("invalid evaluation mode"); 44 | } 45 | 46 | PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr()); 47 | if (!result) 48 | throw error_already_set(); 49 | return reinterpret_steal(result); 50 | } 51 | 52 | template 53 | object eval(const char (&s)[N], object global = globals(), object local = object()) { 54 | /* Support raw string literals by removing common leading whitespace */ 55 | auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s)) 56 | : str(s); 57 | return eval(expr, global, local); 58 | } 59 | 60 | inline void exec(str expr, object global = globals(), object local = object()) { 61 | eval(expr, global, local); 62 | } 63 | 64 | template 65 | void exec(const char (&s)[N], object global = globals(), object local = object()) { 66 | eval(s, global, local); 67 | } 68 | 69 | template 70 | object eval_file(str fname, object global = globals(), object local = object()) { 71 | if (!local) 72 | local = global; 73 | 74 | int start; 75 | switch (mode) { 76 | case eval_expr: start = Py_eval_input; break; 77 | case eval_single_statement: start = Py_single_input; break; 78 | case eval_statements: start = Py_file_input; break; 79 | default: pybind11_fail("invalid evaluation mode"); 80 | } 81 | 82 | int closeFile = 1; 83 | std::string fname_str = (std::string) fname; 84 | #if PY_VERSION_HEX >= 0x03040000 85 | FILE *f = _Py_fopen_obj(fname.ptr(), "r"); 86 | #elif PY_VERSION_HEX >= 0x03000000 87 | FILE *f = _Py_fopen(fname.ptr(), "r"); 88 | #else 89 | /* No unicode support in open() :( */ 90 | auto fobj = reinterpret_steal(PyFile_FromString( 91 | const_cast(fname_str.c_str()), 92 | const_cast("r"))); 93 | FILE *f = nullptr; 94 | if (fobj) 95 | f = PyFile_AsFile(fobj.ptr()); 96 | closeFile = 0; 97 | #endif 98 | if (!f) { 99 | PyErr_Clear(); 100 | pybind11_fail("File \"" + fname_str + "\" could not be opened!"); 101 | } 102 | 103 | #if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION) 104 | PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), 105 | local.ptr()); 106 | (void) closeFile; 107 | #else 108 | PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), 109 | local.ptr(), closeFile); 110 | #endif 111 | 112 | if (!result) 113 | throw error_already_set(); 114 | return reinterpret_steal(result); 115 | } 116 | 117 | NAMESPACE_END(PYBIND11_NAMESPACE) 118 | -------------------------------------------------------------------------------- /nms/include/pybind11/functional.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/functional.h: std::function<> support 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | #include "../../../nms/include/pybind11/pybind11.h" 14 | 15 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 16 | NAMESPACE_BEGIN(detail) 17 | 18 | template 19 | struct type_caster> { 20 | using type = std::function; 21 | using retval_type = conditional_t::value, void_type, Return>; 22 | using function_type = Return (*) (Args...); 23 | 24 | public: 25 | bool load(handle src, bool convert) { 26 | if (src.is_none()) { 27 | // Defer accepting None to other overloads (if we aren't in convert mode): 28 | if (!convert) return false; 29 | return true; 30 | } 31 | 32 | if (!isinstance(src)) 33 | return false; 34 | 35 | auto func = reinterpret_borrow(src); 36 | 37 | /* 38 | When passing a C++ function as an argument to another C++ 39 | function via Python, every function call would normally involve 40 | a full C++ -> Python -> C++ roundtrip, which can be prohibitive. 41 | Here, we try to at least detect the case where the function is 42 | stateless (i.e. function pointer or lambda function without 43 | captured variables), in which case the roundtrip can be avoided. 44 | */ 45 | if (auto cfunc = func.cpp_function()) { 46 | auto c = reinterpret_borrow(PyCFunction_GET_SELF(cfunc.ptr())); 47 | auto rec = (function_record *) c; 48 | 49 | if (rec && rec->is_stateless && 50 | same_type(typeid(function_type), *reinterpret_cast(rec->data[1]))) { 51 | struct capture { function_type f; }; 52 | value = ((capture *) &rec->data)->f; 53 | return true; 54 | } 55 | } 56 | 57 | value = [func](Args... args) -> Return { 58 | gil_scoped_acquire acq; 59 | object retval(func(std::forward(args)...)); 60 | /* Visual studio 2015 parser issue: need parentheses around this expression */ 61 | return (retval.template cast()); 62 | }; 63 | return true; 64 | } 65 | 66 | template 67 | static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) { 68 | if (!f_) 69 | return none().inc_ref(); 70 | 71 | auto result = f_.template target(); 72 | if (result) 73 | return cpp_function(*result, policy).release(); 74 | else 75 | return cpp_function(std::forward(f_), policy).release(); 76 | } 77 | 78 | PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster::name...) + _("], ") 79 | + make_caster::name + _("]")); 80 | }; 81 | 82 | NAMESPACE_END(detail) 83 | NAMESPACE_END(PYBIND11_NAMESPACE) 84 | -------------------------------------------------------------------------------- /nms/include/pybind11/iostream.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python 3 | 4 | Copyright (c) 2017 Henry F. Schreiner 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "../../../nms/include/pybind11/pybind11.h" 18 | 19 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 20 | NAMESPACE_BEGIN(detail) 21 | 22 | // Buffer that writes to Python instead of C++ 23 | class pythonbuf : public std::streambuf { 24 | private: 25 | using traits_type = std::streambuf::traits_type; 26 | 27 | char d_buffer[1024]; 28 | object pywrite; 29 | object pyflush; 30 | 31 | int overflow(int c) { 32 | if (!traits_type::eq_int_type(c, traits_type::eof())) { 33 | *pptr() = traits_type::to_char_type(c); 34 | pbump(1); 35 | } 36 | return sync() ? traits_type::not_eof(c) : traits_type::eof(); 37 | } 38 | 39 | int sync() { 40 | if (pbase() != pptr()) { 41 | // This subtraction cannot be negative, so dropping the sign 42 | str line(pbase(), static_cast(pptr() - pbase())); 43 | 44 | pywrite(line); 45 | pyflush(); 46 | 47 | setp(pbase(), epptr()); 48 | } 49 | return 0; 50 | } 51 | 52 | public: 53 | pythonbuf(object pyostream) 54 | : pywrite(pyostream.attr("write")), 55 | pyflush(pyostream.attr("flush")) { 56 | setp(d_buffer, d_buffer + sizeof(d_buffer) - 1); 57 | } 58 | 59 | /// Sync before destroy 60 | ~pythonbuf() { 61 | sync(); 62 | } 63 | }; 64 | 65 | NAMESPACE_END(detail) 66 | 67 | 68 | /** \rst 69 | This a move-only guard that redirects output. 70 | 71 | .. code-block:: cpp 72 | 73 | #include 74 | 75 | ... 76 | 77 | { 78 | py::scoped_ostream_redirect output; 79 | std::cout << "Hello, World!"; // Python stdout 80 | } // <-- return std::cout to normal 81 | 82 | You can explicitly pass the c++ stream and the python object, 83 | for example to guard stderr instead. 84 | 85 | .. code-block:: cpp 86 | 87 | { 88 | py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")}; 89 | std::cerr << "Hello, World!"; 90 | } 91 | \endrst */ 92 | class scoped_ostream_redirect { 93 | protected: 94 | std::streambuf *old; 95 | std::ostream &costream; 96 | detail::pythonbuf buffer; 97 | 98 | public: 99 | scoped_ostream_redirect( 100 | std::ostream &costream = std::cout, 101 | object pyostream = module::import("sys").attr("stdout")) 102 | : costream(costream), buffer(pyostream) { 103 | old = costream.rdbuf(&buffer); 104 | } 105 | 106 | ~scoped_ostream_redirect() { 107 | costream.rdbuf(old); 108 | } 109 | 110 | scoped_ostream_redirect(const scoped_ostream_redirect &) = delete; 111 | scoped_ostream_redirect(scoped_ostream_redirect &&other) = default; 112 | scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete; 113 | scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete; 114 | }; 115 | 116 | 117 | /** \rst 118 | Like `scoped_ostream_redirect`, but redirects cerr by default. This class 119 | is provided primary to make ``py::call_guard`` easier to make. 120 | 121 | .. code-block:: cpp 122 | 123 | m.def("noisy_func", &noisy_func, 124 | py::call_guard()); 126 | 127 | \endrst */ 128 | class scoped_estream_redirect : public scoped_ostream_redirect { 129 | public: 130 | scoped_estream_redirect( 131 | std::ostream &costream = std::cerr, 132 | object pyostream = module::import("sys").attr("stderr")) 133 | : scoped_ostream_redirect(costream,pyostream) {} 134 | }; 135 | 136 | 137 | NAMESPACE_BEGIN(detail) 138 | 139 | // Class to redirect output as a context manager. C++ backend. 140 | class OstreamRedirect { 141 | bool do_stdout_; 142 | bool do_stderr_; 143 | std::unique_ptr redirect_stdout; 144 | std::unique_ptr redirect_stderr; 145 | 146 | public: 147 | OstreamRedirect(bool do_stdout = true, bool do_stderr = true) 148 | : do_stdout_(do_stdout), do_stderr_(do_stderr) {} 149 | 150 | void enter() { 151 | if (do_stdout_) 152 | redirect_stdout.reset(new scoped_ostream_redirect()); 153 | if (do_stderr_) 154 | redirect_stderr.reset(new scoped_estream_redirect()); 155 | } 156 | 157 | void exit() { 158 | redirect_stdout.reset(); 159 | redirect_stderr.reset(); 160 | } 161 | }; 162 | 163 | NAMESPACE_END(detail) 164 | 165 | /** \rst 166 | This is a helper function to add a C++ redirect context manager to Python 167 | instead of using a C++ guard. To use it, add the following to your binding code: 168 | 169 | .. code-block:: cpp 170 | 171 | #include 172 | 173 | ... 174 | 175 | py::add_ostream_redirect(m, "ostream_redirect"); 176 | 177 | You now have a Python context manager that redirects your output: 178 | 179 | .. code-block:: python 180 | 181 | with m.ostream_redirect(): 182 | m.print_to_cout_function() 183 | 184 | This manager can optionally be told which streams to operate on: 185 | 186 | .. code-block:: python 187 | 188 | with m.ostream_redirect(stdout=true, stderr=true): 189 | m.noisy_function_with_error_printing() 190 | 191 | \endrst */ 192 | inline class_ add_ostream_redirect(module m, std::string name = "ostream_redirect") { 193 | return class_(m, name.c_str(), module_local()) 194 | .def(init(), arg("stdout")=true, arg("stderr")=true) 195 | .def("__enter__", &detail::OstreamRedirect::enter) 196 | .def("__exit__", [](detail::OstreamRedirect &self, args) { self.exit(); }); 197 | } 198 | 199 | NAMESPACE_END(PYBIND11_NAMESPACE) 200 | -------------------------------------------------------------------------------- /nms/include/pybind11/operators.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/operator.h: Metatemplates for operator overloading 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "../../../nms/include/pybind11/pybind11.h" 13 | 14 | #if defined(__clang__) && !defined(__INTEL_COMPILER) 15 | # pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type())) 16 | #elif defined(_MSC_VER) 17 | # pragma warning(push) 18 | # pragma warning(disable: 4127) // warning C4127: Conditional expression is constant 19 | #endif 20 | 21 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 22 | NAMESPACE_BEGIN(detail) 23 | 24 | /// Enumeration with all supported operator types 25 | enum op_id : int { 26 | op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift, 27 | op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert, 28 | op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le, 29 | op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift, 30 | op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero, 31 | op_repr, op_truediv, op_itruediv, op_hash 32 | }; 33 | 34 | enum op_type : int { 35 | op_l, /* base type on left */ 36 | op_r, /* base type on right */ 37 | op_u /* unary operator */ 38 | }; 39 | 40 | struct self_t { }; 41 | static const self_t self = self_t(); 42 | 43 | /// Type for an unused type slot 44 | struct undefined_t { }; 45 | 46 | /// Don't warn about an unused variable 47 | inline self_t __self() { return self; } 48 | 49 | /// base template of operator implementations 50 | template struct op_impl { }; 51 | 52 | /// Operator implementation generator 53 | template struct op_ { 54 | template void execute(Class &cl, const Extra&... extra) const { 55 | using Base = typename Class::type; 56 | using L_type = conditional_t::value, Base, L>; 57 | using R_type = conditional_t::value, Base, R>; 58 | using op = op_impl; 59 | cl.def(op::name(), &op::execute, is_operator(), extra...); 60 | #if PY_MAJOR_VERSION < 3 61 | if (id == op_truediv || id == op_itruediv) 62 | cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__", 63 | &op::execute, is_operator(), extra...); 64 | #endif 65 | } 66 | template void execute_cast(Class &cl, const Extra&... extra) const { 67 | using Base = typename Class::type; 68 | using L_type = conditional_t::value, Base, L>; 69 | using R_type = conditional_t::value, Base, R>; 70 | using op = op_impl; 71 | cl.def(op::name(), &op::execute_cast, is_operator(), extra...); 72 | #if PY_MAJOR_VERSION < 3 73 | if (id == op_truediv || id == op_itruediv) 74 | cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__", 75 | &op::execute, is_operator(), extra...); 76 | #endif 77 | } 78 | }; 79 | 80 | #define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \ 81 | template struct op_impl { \ 82 | static char const* name() { return "__" #id "__"; } \ 83 | static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \ 84 | static B execute_cast(const L &l, const R &r) { return B(expr); } \ 85 | }; \ 86 | template struct op_impl { \ 87 | static char const* name() { return "__" #rid "__"; } \ 88 | static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \ 89 | static B execute_cast(const R &r, const L &l) { return B(expr); } \ 90 | }; \ 91 | inline op_ op(const self_t &, const self_t &) { \ 92 | return op_(); \ 93 | } \ 94 | template op_ op(const self_t &, const T &) { \ 95 | return op_(); \ 96 | } \ 97 | template op_ op(const T &, const self_t &) { \ 98 | return op_(); \ 99 | } 100 | 101 | #define PYBIND11_INPLACE_OPERATOR(id, op, expr) \ 102 | template struct op_impl { \ 103 | static char const* name() { return "__" #id "__"; } \ 104 | static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \ 105 | static B execute_cast(L &l, const R &r) { return B(expr); } \ 106 | }; \ 107 | template op_ op(const self_t &, const T &) { \ 108 | return op_(); \ 109 | } 110 | 111 | #define PYBIND11_UNARY_OPERATOR(id, op, expr) \ 112 | template struct op_impl { \ 113 | static char const* name() { return "__" #id "__"; } \ 114 | static auto execute(const L &l) -> decltype(expr) { return expr; } \ 115 | static B execute_cast(const L &l) { return B(expr); } \ 116 | }; \ 117 | inline op_ op(const self_t &) { \ 118 | return op_(); \ 119 | } 120 | 121 | PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r) 122 | PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r) 123 | PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r) 124 | PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r) 125 | PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r) 126 | PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r) 127 | PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r) 128 | PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r) 129 | PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r) 130 | PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r) 131 | PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r) 132 | PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r) 133 | PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r) 134 | PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r) 135 | PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r) 136 | PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r) 137 | //PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r)) 138 | PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r) 139 | PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r) 140 | PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r) 141 | PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r) 142 | PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r) 143 | PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r) 144 | PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r) 145 | PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r) 146 | PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r) 147 | PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r) 148 | PYBIND11_UNARY_OPERATOR(neg, operator-, -l) 149 | PYBIND11_UNARY_OPERATOR(pos, operator+, +l) 150 | PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l)) 151 | PYBIND11_UNARY_OPERATOR(hash, hash, std::hash()(l)) 152 | PYBIND11_UNARY_OPERATOR(invert, operator~, (~l)) 153 | PYBIND11_UNARY_OPERATOR(bool, operator!, !!l) 154 | PYBIND11_UNARY_OPERATOR(int, int_, (int) l) 155 | PYBIND11_UNARY_OPERATOR(float, float_, (double) l) 156 | 157 | #undef PYBIND11_BINARY_OPERATOR 158 | #undef PYBIND11_INPLACE_OPERATOR 159 | #undef PYBIND11_UNARY_OPERATOR 160 | NAMESPACE_END(detail) 161 | 162 | using detail::self; 163 | 164 | NAMESPACE_END(PYBIND11_NAMESPACE) 165 | 166 | #if defined(_MSC_VER) 167 | # pragma warning(pop) 168 | #endif 169 | -------------------------------------------------------------------------------- /nms/include/pybind11/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/options.h: global settings that are configurable at runtime. 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "../../../nms/include/pybind11/detail/common.h" 13 | 14 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 15 | 16 | class options { 17 | public: 18 | 19 | // Default RAII constructor, which leaves settings as they currently are. 20 | options() : previous_state(global_state()) {} 21 | 22 | // Class is non-copyable. 23 | options(const options&) = delete; 24 | options& operator=(const options&) = delete; 25 | 26 | // Destructor, which restores settings that were in effect before. 27 | ~options() { 28 | global_state() = previous_state; 29 | } 30 | 31 | // Setter methods (affect the global state): 32 | 33 | options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; } 34 | 35 | options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; } 36 | 37 | options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; } 38 | 39 | options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; } 40 | 41 | // Getter methods (return the global state): 42 | 43 | static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; } 44 | 45 | static bool show_function_signatures() { return global_state().show_function_signatures; } 46 | 47 | // This type is not meant to be allocated on the heap. 48 | void* operator new(size_t) = delete; 49 | 50 | private: 51 | 52 | struct state { 53 | bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings. 54 | bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings. 55 | }; 56 | 57 | static state &global_state() { 58 | static state instance; 59 | return instance; 60 | } 61 | 62 | state previous_state; 63 | }; 64 | 65 | NAMESPACE_END(PYBIND11_NAMESPACE) 66 | -------------------------------------------------------------------------------- /nms/include/pybind11/stl.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/stl.h: Transparent conversion for STL data types 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "../../../nms/include/pybind11/pybind11.h" 20 | 21 | #if defined(_MSC_VER) 22 | #pragma warning(push) 23 | #pragma warning(disable: 4127) // warning C4127: Conditional expression is constant 24 | #endif 25 | 26 | #ifdef __has_include 27 | // std::optional (but including it in c++14 mode isn't allowed) 28 | # if defined(PYBIND11_CPP17) && __has_include() 29 | # include 30 | # define PYBIND11_HAS_OPTIONAL 1 31 | # endif 32 | // std::experimental::optional (but not allowed in c++11 mode) 33 | # if defined(PYBIND11_CPP14) && (__has_include() && \ 34 | !__has_include()) 35 | # include 36 | # define PYBIND11_HAS_EXP_OPTIONAL 1 37 | # endif 38 | // std::variant 39 | # if defined(PYBIND11_CPP17) && __has_include() 40 | # include 41 | # define PYBIND11_HAS_VARIANT 1 42 | # endif 43 | #elif defined(_MSC_VER) && defined(PYBIND11_CPP17) 44 | # include 45 | # include 46 | # define PYBIND11_HAS_OPTIONAL 1 47 | # define PYBIND11_HAS_VARIANT 1 48 | #endif 49 | 50 | NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 51 | NAMESPACE_BEGIN(detail) 52 | 53 | /// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for 54 | /// forwarding a container element). Typically used indirect via forwarded_type(), below. 55 | template 56 | using forwarded_type = conditional_t< 57 | std::is_lvalue_reference::value, remove_reference_t &, remove_reference_t &&>; 58 | 59 | /// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically 60 | /// used for forwarding a container's elements. 61 | template 62 | forwarded_type forward_like(U &&u) { 63 | return std::forward>(std::forward(u)); 64 | } 65 | 66 | template struct set_caster { 67 | using type = Type; 68 | using key_conv = make_caster; 69 | 70 | bool load(handle src, bool convert) { 71 | if (!isinstance(src)) 72 | return false; 73 | auto s = reinterpret_borrow(src); 74 | value.clear(); 75 | for (auto entry : s) { 76 | key_conv conv; 77 | if (!conv.load(entry, convert)) 78 | return false; 79 | value.insert(cast_op(std::move(conv))); 80 | } 81 | return true; 82 | } 83 | 84 | template 85 | static handle cast(T &&src, return_value_policy policy, handle parent) { 86 | pybind11::set s; 87 | for (auto &&value : src) { 88 | auto value_ = reinterpret_steal(key_conv::cast(forward_like(value), policy, parent)); 89 | if (!value_ || !s.add(value_)) 90 | return handle(); 91 | } 92 | return s.release(); 93 | } 94 | 95 | PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]")); 96 | }; 97 | 98 | template struct map_caster { 99 | using key_conv = make_caster; 100 | using value_conv = make_caster; 101 | 102 | bool load(handle src, bool convert) { 103 | if (!isinstance(src)) 104 | return false; 105 | auto d = reinterpret_borrow(src); 106 | value.clear(); 107 | for (auto it : d) { 108 | key_conv kconv; 109 | value_conv vconv; 110 | if (!kconv.load(it.first.ptr(), convert) || 111 | !vconv.load(it.second.ptr(), convert)) 112 | return false; 113 | value.emplace(cast_op(std::move(kconv)), cast_op(std::move(vconv))); 114 | } 115 | return true; 116 | } 117 | 118 | template 119 | static handle cast(T &&src, return_value_policy policy, handle parent) { 120 | dict d; 121 | for (auto &&kv : src) { 122 | auto key = reinterpret_steal(key_conv::cast(forward_like(kv.first), policy, parent)); 123 | auto value = reinterpret_steal(value_conv::cast(forward_like(kv.second), policy, parent)); 124 | if (!key || !value) 125 | return handle(); 126 | d[key] = value; 127 | } 128 | return d.release(); 129 | } 130 | 131 | PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]")); 132 | }; 133 | 134 | template struct list_caster { 135 | using value_conv = make_caster; 136 | 137 | bool load(handle src, bool convert) { 138 | if (!isinstance(src)) 139 | return false; 140 | auto s = reinterpret_borrow(src); 141 | value.clear(); 142 | reserve_maybe(s, &value); 143 | for (auto it : s) { 144 | value_conv conv; 145 | if (!conv.load(it, convert)) 146 | return false; 147 | value.push_back(cast_op(std::move(conv))); 148 | } 149 | return true; 150 | } 151 | 152 | private: 153 | template ().reserve(0)), void>::value, int> = 0> 155 | void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); } 156 | void reserve_maybe(sequence, void *) { } 157 | 158 | public: 159 | template 160 | static handle cast(T &&src, return_value_policy policy, handle parent) { 161 | list l(src.size()); 162 | size_t index = 0; 163 | for (auto &&value : src) { 164 | auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); 165 | if (!value_) 166 | return handle(); 167 | PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference 168 | } 169 | return l.release(); 170 | } 171 | 172 | PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]")); 173 | }; 174 | 175 | template struct type_caster> 176 | : list_caster, Type> { }; 177 | 178 | template struct type_caster> 179 | : list_caster, Type> { }; 180 | 181 | template struct array_caster { 182 | using value_conv = make_caster; 183 | 184 | private: 185 | template 186 | bool require_size(enable_if_t size) { 187 | if (value.size() != size) 188 | value.resize(size); 189 | return true; 190 | } 191 | template 192 | bool require_size(enable_if_t size) { 193 | return size == Size; 194 | } 195 | 196 | public: 197 | bool load(handle src, bool convert) { 198 | if (!isinstance(src)) 199 | return false; 200 | auto l = reinterpret_borrow(src); 201 | if (!require_size(l.size())) 202 | return false; 203 | size_t ctr = 0; 204 | for (auto it : l) { 205 | value_conv conv; 206 | if (!conv.load(it, convert)) 207 | return false; 208 | value[ctr++] = cast_op(std::move(conv)); 209 | } 210 | return true; 211 | } 212 | 213 | template 214 | static handle cast(T &&src, return_value_policy policy, handle parent) { 215 | list l(src.size()); 216 | size_t index = 0; 217 | for (auto &&value : src) { 218 | auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); 219 | if (!value_) 220 | return handle(); 221 | PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference 222 | } 223 | return l.release(); 224 | } 225 | 226 | PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _(_(""), _("[") + _() + _("]")) + _("]")); 227 | }; 228 | 229 | template struct type_caster> 230 | : array_caster, Type, false, Size> { }; 231 | 232 | template struct type_caster> 233 | : array_caster, Type, true> { }; 234 | 235 | template struct type_caster> 236 | : set_caster, Key> { }; 237 | 238 | template struct type_caster> 239 | : set_caster, Key> { }; 240 | 241 | template struct type_caster> 242 | : map_caster, Key, Value> { }; 243 | 244 | template struct type_caster> 245 | : map_caster, Key, Value> { }; 246 | 247 | // This type caster is intended to be used for std::optional and std::experimental::optional 248 | template struct optional_caster { 249 | using value_conv = make_caster; 250 | 251 | template 252 | static handle cast(T_ &&src, return_value_policy policy, handle parent) { 253 | if (!src) 254 | return none().inc_ref(); 255 | return value_conv::cast(*std::forward(src), policy, parent); 256 | } 257 | 258 | bool load(handle src, bool convert) { 259 | if (!src) { 260 | return false; 261 | } else if (src.is_none()) { 262 | return true; // default-constructed value is already empty 263 | } 264 | value_conv inner_caster; 265 | if (!inner_caster.load(src, convert)) 266 | return false; 267 | 268 | value.emplace(cast_op(std::move(inner_caster))); 269 | return true; 270 | } 271 | 272 | PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]")); 273 | }; 274 | 275 | #if PYBIND11_HAS_OPTIONAL 276 | template struct type_caster> 277 | : public optional_caster> {}; 278 | 279 | template<> struct type_caster 280 | : public void_caster {}; 281 | #endif 282 | 283 | #if PYBIND11_HAS_EXP_OPTIONAL 284 | template struct type_caster> 285 | : public optional_caster> {}; 286 | 287 | template<> struct type_caster 288 | : public void_caster {}; 289 | #endif 290 | 291 | /// Visit a variant and cast any found type to Python 292 | struct variant_caster_visitor { 293 | return_value_policy policy; 294 | handle parent; 295 | 296 | using result_type = handle; // required by boost::variant in C++11 297 | 298 | template 299 | result_type operator()(T &&src) const { 300 | return make_caster::cast(std::forward(src), policy, parent); 301 | } 302 | }; 303 | 304 | /// Helper class which abstracts away variant's `visit` function. `std::variant` and similar 305 | /// `namespace::variant` types which provide a `namespace::visit()` function are handled here 306 | /// automatically using argument-dependent lookup. Users can provide specializations for other 307 | /// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`. 308 | template class Variant> 309 | struct visit_helper { 310 | template 311 | static auto call(Args &&...args) -> decltype(visit(std::forward(args)...)) { 312 | return visit(std::forward(args)...); 313 | } 314 | }; 315 | 316 | /// Generic variant caster 317 | template struct variant_caster; 318 | 319 | template class V, typename... Ts> 320 | struct variant_caster> { 321 | static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative."); 322 | 323 | template 324 | bool load_alternative(handle src, bool convert, type_list) { 325 | auto caster = make_caster(); 326 | if (caster.load(src, convert)) { 327 | value = cast_op(caster); 328 | return true; 329 | } 330 | return load_alternative(src, convert, type_list{}); 331 | } 332 | 333 | bool load_alternative(handle, bool, type_list<>) { return false; } 334 | 335 | bool load(handle src, bool convert) { 336 | // Do a first pass without conversions to improve constructor resolution. 337 | // E.g. `py::int_(1).cast>()` needs to fill the `int` 338 | // slot of the variant. Without two-pass loading `double` would be filled 339 | // because it appears first and a conversion is possible. 340 | if (convert && load_alternative(src, false, type_list{})) 341 | return true; 342 | return load_alternative(src, convert, type_list{}); 343 | } 344 | 345 | template 346 | static handle cast(Variant &&src, return_value_policy policy, handle parent) { 347 | return visit_helper::call(variant_caster_visitor{policy, parent}, 348 | std::forward(src)); 349 | } 350 | 351 | using Type = V; 352 | PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster::name...) + _("]")); 353 | }; 354 | 355 | #if PYBIND11_HAS_VARIANT 356 | template 357 | struct type_caster> : variant_caster> { }; 358 | #endif 359 | NAMESPACE_END(detail) 360 | 361 | inline std::ostream &operator<<(std::ostream &os, const handle &obj) { 362 | os << (std::string) str(obj); 363 | return os; 364 | } 365 | 366 | NAMESPACE_END(PYBIND11_NAMESPACE) 367 | 368 | #if defined(_MSC_VER) 369 | #pragma warning(pop) 370 | #endif 371 | -------------------------------------------------------------------------------- /nms/nms.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../nms/include/clipper/clipper.hpp" 4 | 5 | namespace nms { 6 | 7 | namespace cl = ClipperLib; 8 | 9 | struct Polygon { 10 | cl::Path poly; 11 | float score; 12 | float probs[4]; 13 | int x; 14 | int y; 15 | std::int32_t nr_polys; 16 | }; 17 | 18 | float paths_area(const ClipperLib::Paths &ps) { 19 | float area = 0; 20 | for (auto &&p: ps) 21 | area += cl::Area(p); 22 | return area; 23 | } 24 | 25 | float poly_iou(const Polygon &a, const Polygon &b) { 26 | cl::Clipper clpr; 27 | clpr.AddPath(a.poly, cl::ptSubject, true); 28 | clpr.AddPath(b.poly, cl::ptClip, true); 29 | 30 | cl::Paths inter, uni; 31 | clpr.Execute(cl::ctIntersection, inter, cl::pftEvenOdd); 32 | clpr.Execute(cl::ctUnion, uni, cl::pftEvenOdd); 33 | 34 | auto inter_area = paths_area(inter), 35 | uni_area = paths_area(uni); 36 | return std::abs(inter_area) / std::max(std::abs(uni_area), 1.0f); 37 | } 38 | 39 | bool should_merge(const Polygon &a, const Polygon &b, float iou_threshold) { 40 | return poly_iou(a, b) > iou_threshold; 41 | } 42 | 43 | /** 44 | * Incrementally merge polygons 45 | */ 46 | class PolyMerger { 47 | public: 48 | PolyMerger(): score(0), nr_polys(0) { 49 | memset(data, 0, sizeof(data)); 50 | memset(probs, 0, 4 * sizeof(float)); 51 | } 52 | 53 | /** 54 | * Add a new polygon to be merged. 55 | */ 56 | void add(const Polygon &p) { 57 | 58 | auto &poly = p.poly; 59 | data[0] += poly[0].X * p.probs[0]; 60 | data[1] += poly[0].Y * p.probs[3]; 61 | 62 | data[2] += poly[1].X * p.probs[0]; 63 | data[3] += poly[1].Y * p.probs[1]; 64 | 65 | data[4] += poly[2].X * p.probs[2]; 66 | data[5] += poly[2].Y * p.probs[1]; 67 | 68 | data[6] += poly[3].X * p.probs[2]; 69 | data[7] += poly[3].Y * p.probs[3]; 70 | 71 | score += p.score; 72 | 73 | probs[0] += p.probs[0]; 74 | probs[1] += p.probs[1]; 75 | probs[2] += p.probs[2]; 76 | probs[3] += p.probs[3]; 77 | 78 | nr_polys += p.nr_polys; 79 | } 80 | 81 | Polygon get() const { 82 | Polygon p; 83 | 84 | auto &poly = p.poly; 85 | poly.resize(4); 86 | 87 | poly[0].X = data[0] / probs[0]; 88 | poly[0].Y = data[1] / probs[3]; 89 | poly[1].X = data[2] / probs[0]; 90 | poly[1].Y = data[3] / probs[1]; 91 | poly[2].X = data[4] / probs[2]; 92 | poly[2].Y = data[5] / probs[1]; 93 | poly[3].X = data[6] / probs[2]; 94 | poly[3].Y = data[7] / probs[3]; 95 | 96 | assert(score > 0); 97 | p.score = score; 98 | p.probs[0] = probs[0]; 99 | p.probs[1] = probs[1]; 100 | p.probs[2] = probs[2]; 101 | p.probs[3] = probs[3]; 102 | p.nr_polys = nr_polys; 103 | 104 | return p; 105 | } 106 | 107 | private: 108 | std::int64_t data[8]; 109 | float score; 110 | float probs[4]; 111 | std::int32_t nr_polys; 112 | }; 113 | 114 | 115 | /** 116 | * The standard NMS algorithm. 117 | */ 118 | std::vector standard_nms(std::vector &polys, float iou_threshold) { 119 | size_t n = polys.size(); 120 | if (n == 0) 121 | return {}; 122 | std::vector indices(n); 123 | std::iota(std::begin(indices), std::end(indices), 0); 124 | std::sort(std::begin(indices), std::end(indices), [&](size_t i, size_t j) { return polys[i].score > polys[j].score; }); 125 | 126 | std::vector keep; 127 | while (indices.size()) { 128 | size_t p = 0, cur = indices[0]; 129 | keep.emplace_back(cur); 130 | for (size_t i = 1; i < indices.size(); i ++) { 131 | if (!should_merge(polys[cur], polys[indices[i]], iou_threshold)) { 132 | indices[p++] = indices[i]; 133 | }else{ 134 | PolyMerger merger; 135 | merger.add(polys[ indices[i]]); 136 | merger.add(polys[cur]); 137 | polys[cur] = merger.get(); 138 | } 139 | } 140 | indices.resize(p); 141 | } 142 | 143 | std::vector ret; 144 | for (auto &&i: keep) { 145 | ret.emplace_back(polys[i]); 146 | } 147 | return ret; 148 | } 149 | 150 | 151 | std::vector 152 | merge_iou(std::vector& polys_in, int* poly_ptr, int w, int h, float iou_threshold1, float iou_threshold2) { 153 | 154 | // first pass 155 | std::vector polys; 156 | for (size_t i = 0; i < polys_in.size(); i ++) { 157 | auto poly = polys_in[i]; 158 | 159 | if (polys.size()) { 160 | // merge with the last one 161 | auto &bpoly = polys.back(); 162 | if (should_merge(poly, bpoly, iou_threshold1)) { 163 | PolyMerger merger; 164 | merger.add(bpoly); 165 | merger.add(poly); 166 | bpoly = merger.get(); 167 | poly_ptr[poly.y * w + poly.x] = (polys.size() - 1); 168 | continue; 169 | }else{ 170 | if(poly.y > 0){ 171 | int idx = poly_ptr[(poly.y -1)* w + poly.x]; 172 | if(idx >= 0){ 173 | auto &cpoly = polys[idx]; 174 | if (should_merge(poly, cpoly, iou_threshold1)) { 175 | PolyMerger merger; 176 | merger.add(cpoly); 177 | merger.add(poly); 178 | cpoly = merger.get(); 179 | poly_ptr[poly.y * w + poly.x] = idx; 180 | continue; 181 | } 182 | if(poly.x > 0){ 183 | idx = poly_ptr[(poly.y -1)* w + poly.x - 1]; 184 | if(idx >= 0){ 185 | auto &cpoly = polys[idx]; 186 | if (should_merge(poly, cpoly, iou_threshold1)) { 187 | PolyMerger merger; 188 | merger.add(cpoly); 189 | merger.add(poly); 190 | cpoly = merger.get(); 191 | poly_ptr[poly.y * w + poly.x] = idx; 192 | continue; 193 | } 194 | } 195 | } 196 | idx = poly_ptr[(poly.y -1)* w + poly.x + 1]; 197 | if(idx >= 0){ 198 | auto &cpoly = polys[idx]; 199 | if (should_merge(poly, cpoly, iou_threshold1)) { 200 | PolyMerger merger; 201 | merger.add(cpoly); 202 | merger.add(poly); 203 | cpoly = merger.get(); 204 | poly_ptr[poly.y * w + poly.x] = idx; 205 | continue; 206 | } 207 | } 208 | } 209 | } 210 | polys.emplace_back(poly); 211 | } 212 | } 213 | polys.emplace_back(poly); 214 | poly_ptr[poly.y * w + poly.x] = (polys.size() - 1); 215 | } 216 | return standard_nms(polys, iou_threshold2); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /ocr_gen.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import csv 3 | import cv2 4 | import time 5 | import os 6 | import numpy as np 7 | import random 8 | 9 | from data_util import GeneratorEnqueuer 10 | 11 | import PIL 12 | import torchvision.transforms as transforms 13 | 14 | use_pyblur = 0 15 | 16 | if use_pyblur == 1: 17 | from pyblur import RandomizedBlur 18 | 19 | buckets = [] 20 | for i in range(1, 100): 21 | buckets.append(8 + 4 * i) 22 | 23 | 24 | import unicodedata as ud 25 | 26 | f = open('codec.txt', 'r') 27 | codec = f.readlines()[0] 28 | codec_rev = {} 29 | index = 4 30 | for i in range(0, len(codec)): 31 | codec_rev[codec[i]] = index 32 | index += 1 33 | 34 | def get_images(data_path): 35 | 36 | base_dir = os.path.dirname(data_path) 37 | files_out = [] 38 | cnt = 0 39 | with open(data_path) as f: 40 | while True: 41 | line = f.readline() 42 | if not line: 43 | break 44 | line = line.strip() 45 | if len(line) == 0: 46 | continue 47 | if not line[0] == '/': 48 | line = '{0}/{1}'.format(base_dir, line) 49 | files_out.append(line) 50 | cnt +=1 51 | #if cnt > 100: 52 | # break 53 | return files_out 54 | 55 | 56 | 57 | def generator(batch_size=4, train_list='/home/klara/klara/home/DeepSemanticText/resources/ims2.txt', in_train=True, rgb = False, norm_height = 32): 58 | image_list = np.array(get_images(train_list)) 59 | print('{} training images in {}'.format(image_list.shape[0], train_list)) 60 | index = np.arange(0, image_list.shape[0]) 61 | 62 | transform = transforms.Compose([ 63 | transforms.ColorJitter(.3,.3,.3,.3), 64 | transforms.RandomGrayscale(p=0.1) 65 | ]) 66 | 67 | batch_sizes = [] 68 | cb = batch_size 69 | for i in range(0, len(buckets)): 70 | batch_sizes.append(cb) 71 | if i % 10 == 0 and cb > 2: 72 | cb /=2 73 | 74 | max_samples = len(image_list) - 1 75 | bucket_images = [] 76 | bucket_labels = [] 77 | bucket_label_len = [] 78 | 79 | for b in range(0, len(buckets)): 80 | bucket_images.append([]) 81 | bucket_labels.append([]) 82 | bucket_label_len.append([]) 83 | 84 | while True: 85 | if in_train: 86 | np.random.shuffle(index) 87 | 88 | for i in index: 89 | try: 90 | image_name = image_list[i] 91 | 92 | src_del = " " 93 | spl = image_name.split(" ") 94 | if len(spl) == 1: 95 | spl = image_name.split(",") 96 | src_del = "," 97 | image_name = spl[0].strip() 98 | gt_txt = '' 99 | if len(spl) > 1: 100 | gt_txt = "" 101 | delim = "" 102 | for k in range(1, len(spl)): 103 | gt_txt += delim + spl[k] 104 | delim =src_del 105 | if len(gt_txt) > 1 and gt_txt[0] == '"' and gt_txt[-1] == '"': 106 | gt_txt = gt_txt[1:-1] 107 | 108 | if len(gt_txt) == 0: 109 | continue 110 | 111 | 112 | if image_name[len(image_name) - 1] == ',': 113 | image_name = image_name[0:-1] 114 | 115 | if not os.path.exists(image_name): 116 | continue 117 | 118 | if rgb: 119 | im = cv2.imread(image_name) 120 | else: 121 | im = cv2.imread(image_name, cv2.IMREAD_GRAYSCALE) 122 | if im is None: 123 | continue 124 | 125 | if image_name.find('/chinese_0/') != -1: 126 | im = cv2.rotate(im, cv2.ROTATE_90_COUNTERCLOCKWISE) #horizontal chinese text 127 | 128 | if im.shape[0] > im.shape[1] and len(gt_txt) > 4: 129 | #cv2.imshow('bad', im) 130 | #print(image_name) 131 | #cv2.waitKey(0) 132 | continue 133 | 134 | scale = norm_height / float(im.shape[0]) 135 | width = int(im.shape[1] * scale) + random.randint(- 2 * norm_height, 2 * norm_height) 136 | 137 | best_diff = width 138 | bestb = 0 139 | for b in range(0, len(buckets)): 140 | if best_diff > abs(width - buckets[b]): 141 | best_diff = abs(width - buckets[b] ) 142 | bestb = b 143 | 144 | if random.randint(0, 100) < 10: 145 | bestb += random.randint(-1, 1) 146 | bestb = max(0, bestb) 147 | bestb = min(bestb, (len(buckets) - 1)) 148 | 149 | width = buckets[bestb] 150 | im = cv2.resize(im, (int(buckets[bestb]), norm_height)) 151 | if not rgb: 152 | im = im.reshape(im.shape[0],im.shape[1], 1) 153 | 154 | if in_train: 155 | if random.randint(0, 100) < 10: 156 | im = np.invert(im) 157 | if not use_pyblur and random.randint(0, 100) < 10: 158 | im = cv2.blur(im,(3,3)) 159 | if not rgb: 160 | im = im.reshape(im.shape[0],im.shape[1], 1) 161 | 162 | if random.randint(0, 100) < 10: 163 | 164 | warp_mat = cv2.getRotationMatrix2D((im.shape[1] / 2, im.shape[0]/ 2), 0, 1) 165 | warp_mat[0, 1] = random.uniform(-0.1, 0.1) 166 | im = cv2.warpAffine(im, warp_mat, (im.shape[1], im.shape[0])) 167 | 168 | pim = PIL.Image.fromarray(np.uint8(im)) 169 | pim = transform(pim) 170 | 171 | if use_pyblur: 172 | if random.randint(0, 100) < 10: 173 | pim = RandomizedBlur(pim) 174 | 175 | im = np.array(pim) 176 | 177 | bucket_images[bestb].append(im[:, :, :].astype(np.float32)) 178 | 179 | gt_labels = [] 180 | for k in range(len(gt_txt)): 181 | if gt_txt[k] in codec_rev: 182 | gt_labels.append( codec_rev[gt_txt[k]] ) 183 | else: 184 | print('Unknown char: {0}'.format(gt_txt[k]) ) 185 | gt_labels.append( 3 ) 186 | 187 | if 'ARABIC' in ud.name(gt_txt[0]): 188 | gt_labels = gt_labels[::-1] 189 | 190 | bucket_labels[bestb].extend(gt_labels) 191 | bucket_label_len[bestb].append(len(gt_labels)) 192 | 193 | if len(bucket_images[bestb]) == batch_sizes[bestb]: 194 | images = np.asarray(bucket_images[bestb], dtype=np.float) 195 | images /= 128 196 | images -= 1 197 | 198 | yield images, bucket_labels[bestb], bucket_label_len[bestb] 199 | max_samples += 1 200 | max_samples = min(max_samples, len(image_list) - 1) 201 | bucket_images[bestb] = [] 202 | bucket_labels[bestb] = [] 203 | bucket_label_len[bestb] = [] 204 | 205 | except Exception as e: 206 | import traceback 207 | traceback.print_exc() 208 | continue 209 | 210 | if not in_train: 211 | print("finish") 212 | yield None 213 | break 214 | 215 | 216 | def get_batch(num_workers, **kwargs): 217 | try: 218 | enqueuer = GeneratorEnqueuer(generator(**kwargs), use_multiprocessing=True) 219 | enqueuer.start(max_queue_size=24, workers=num_workers) 220 | generator_output = None 221 | while True: 222 | while enqueuer.is_running(): 223 | if not enqueuer.queue.empty(): 224 | generator_output = enqueuer.queue.get() 225 | break 226 | else: 227 | time.sleep(0.01) 228 | yield generator_output 229 | generator_output = None 230 | finally: 231 | if enqueuer is not None: 232 | enqueuer.stop() 233 | 234 | if __name__ == '__main__': 235 | 236 | data_generator = get_batch(num_workers=1, batch_size=1) 237 | while True: 238 | data = next(data_generator) 239 | 240 | -------------------------------------------------------------------------------- /ocr_test_utils.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Nov 3, 2017 3 | 4 | @author: Michal.Busta at gmail.com 5 | ''' 6 | 7 | import os 8 | 9 | import numpy as np 10 | import cv2 11 | 12 | import net_utils 13 | 14 | import unicodedata as ud 15 | 16 | from Levenshtein import distance 17 | import pandas as pd 18 | 19 | from ocr_utils import print_seq_ext 20 | 21 | buckets = [] 22 | for i in range(1, 100): 23 | buckets.append(8 + 8 * i) 24 | 25 | 26 | def test(net, codec, args, list_file = '/home/busta/data/icdar_ch8_validation/ocr_valid.txt', norm_height=32, max_samples=1000000): 27 | 28 | 29 | codec_rev = {} 30 | index = 4 31 | for i in range(0, len(codec)): 32 | codec_rev[codec[i]] = index 33 | index += 1 34 | 35 | 36 | net = net.eval() 37 | #list_file = '/mnt/textspotter/tmp/90kDICT32px/train_list.txt' 38 | #list_file = '/home/busta/data/Challenge2_Test_Task3_Images/gt.txt' 39 | #list_file = '/home/busta/data/90kDICT32px/train_icdar_ch8.txt' 40 | fout = open('/tmp/ch8_valid.txt', 'w') 41 | fout_ocr = open('/tmp/ocr_valid.txt', 'w') 42 | 43 | 44 | dir_name = os.path.dirname(list_file) 45 | images = [] 46 | with open(list_file, "r") as ins: 47 | for line in ins: 48 | images.append(line.strip()) 49 | #if len(images) > 1000: 50 | # break 51 | 52 | scripts = ['', 'DIGIT', 'LATIN', 'ARABIC', 'BENGALI', 'HANGUL', 'CJK', 'HIRAGANA', 'KATAKANA'] 53 | 54 | conf_matrix = np.zeros((len(scripts), len(scripts)), dtype = np.int) 55 | 56 | gt_script = {} 57 | ed_script = {} 58 | correct_ed1_script = {} 59 | correct_script = {} 60 | count_script = {} 61 | for scr in scripts: 62 | gt_script[scr] = 0 63 | ed_script[scr] = 0 64 | correct_script[scr] = 0 65 | correct_ed1_script[scr] = 0 66 | count_script[scr] = 0 67 | 68 | it = 0 69 | it2 = 0 70 | correct = 0 71 | correct_ed1 = 0 72 | ted = 0 73 | gt_all = 0 74 | images_count = 0 75 | bad_words = [] 76 | 77 | for img in images: 78 | 79 | imageNo = it2 80 | #imageNo = random.randint(0, len(images) - 1) 81 | if imageNo >= len(images) or imageNo > max_samples: 82 | break 83 | 84 | 85 | image_name = img 86 | 87 | spl = image_name.split(",") 88 | delim = "," 89 | if len(spl) == 1: 90 | spl = image_name.split(" ") 91 | delim = " " 92 | image_name = spl[0].strip() 93 | gt_txt = '' 94 | if len(spl) > 1: 95 | gt_txt = spl[1].strip() 96 | if len(spl) > 2: 97 | gt_txt += delim + spl[2] 98 | 99 | if len(gt_txt) > 1 and gt_txt[0] == '"' and gt_txt[-1] == '"': 100 | gt_txt = gt_txt[1:len(gt_txt) - 1] 101 | 102 | it2 += 1 103 | if len(gt_txt) == 0: 104 | print(images[imageNo]) 105 | continue 106 | 107 | if image_name[-1] == ',': 108 | image_name = image_name[0:-1] 109 | 110 | img_nameo = image_name 111 | image_name = '{0}/{1}'.format(dir_name, image_name) 112 | img = cv2.imread(image_name) 113 | 114 | if img is None: 115 | print(image_name) 116 | continue 117 | 118 | scale = norm_height / float(img.shape[0]) 119 | width = int(img.shape[1] * scale) 120 | width = max(8, int(round(width / 4)) * 4) 121 | 122 | scaled = cv2.resize(img, (int(width), norm_height)) 123 | #scaled = scaled[:, :, ::-1] 124 | scaled = np.expand_dims(scaled, axis=0) 125 | 126 | scaled = np.asarray(scaled, dtype=np.float) 127 | scaled /= 128 128 | scaled -= 1 129 | 130 | try: 131 | scaled_var = net_utils.np_to_variable(scaled, is_cuda=args.cuda).permute(0, 3, 1, 2) 132 | x = net.forward_features(scaled_var) 133 | ctc_f = net.forward_ocr(x ) 134 | ctc_f = ctc_f.data.cpu().numpy() 135 | ctc_f = ctc_f.swapaxes(1, 2) 136 | 137 | labels = ctc_f.argmax(2) 138 | det_text, conf, dec_s, _ = print_seq_ext(labels[0, :], codec) 139 | except: 140 | print('bad image') 141 | det_text = '' 142 | 143 | det_text = det_text.strip() 144 | gt_txt = gt_txt.strip() 145 | 146 | try: 147 | if 'ARABIC' in ud.name(gt_txt[0]): 148 | #gt_txt = gt_txt[::-1] 149 | det_text = det_text[::-1] 150 | except: 151 | continue 152 | 153 | it += 1 154 | 155 | scr_count = [0, 0, 0, 0, 0, 0, 0, 0, 0] 156 | scr_count = np.array(scr_count) 157 | 158 | for c_char in gt_txt: 159 | assigned = False 160 | for idx, scr in enumerate(scripts): 161 | if idx == 0: 162 | continue 163 | symbol_name = ud.name(c_char) 164 | if scr in symbol_name: 165 | scr_count[idx] += 1 166 | assigned = True 167 | break 168 | if not assigned: 169 | scr_count[0] += 1 170 | 171 | 172 | maximum_indices = np.where(scr_count==np.max(scr_count)) 173 | script = scripts[maximum_indices[0][0]] 174 | 175 | det_count = [0, 0, 0, 0, 0, 0, 0, 0, 0] 176 | det_count = np.array(det_count) 177 | for c_char in det_text: 178 | assigned = False 179 | for idx, scr in enumerate(scripts): 180 | if idx == 0: 181 | continue 182 | try: 183 | symbol_name = ud.name(c_char) 184 | if scr in symbol_name: 185 | det_count[idx] += 1 186 | assigned = True 187 | break 188 | except: 189 | pass 190 | if not assigned: 191 | det_count[0] += 1 192 | 193 | maximum_indices_det = np.where(det_count==np.max(det_count)) 194 | script_det = scripts[maximum_indices_det[0][0]] 195 | 196 | 197 | conf_matrix[maximum_indices[0][0], maximum_indices_det[0][0]] += 1 198 | 199 | edit_dist = distance(det_text.lower(), gt_txt.lower()) 200 | ted += edit_dist 201 | gt_all += len(gt_txt) 202 | 203 | gt_script[script] += len(gt_txt) 204 | ed_script[script] += edit_dist 205 | images_count += 1 206 | 207 | fout_ocr.write('{0}, "{1}"\n'.format(os.path.basename(image_name), det_text.strip())) 208 | 209 | if det_text.lower() == gt_txt.lower(): 210 | correct += 1 211 | correct_ed1 += 1 212 | correct_script[script] += 1 213 | correct_ed1_script[script] += 1 214 | else: 215 | if edit_dist == 1: 216 | correct_ed1 += 1 217 | correct_ed1_script[script] += 1 218 | image_prev = "".format(img_nameo) 219 | bad_words.append((gt_txt, det_text, edit_dist, image_prev, img_nameo)) 220 | print('{0} - {1} / {2:.2f} - {3:.2f}'.format(det_text, gt_txt, correct / float(it), ted / 3.0 )) 221 | 222 | count_script[script] += 1 223 | fout.write('{0}|{1}|{2}|{3}\n'.format(os.path.basename(image_name), gt_txt, det_text, edit_dist)) 224 | 225 | print('Test accuracy: {0:.3f}, {1:.2f}, {2:.3f}'.format(correct / float(images_count), ted / 3.0, ted / float(gt_all) )) 226 | 227 | 228 | itf = open("per_script_accuracy.csv", "w") 229 | itf.write('Script & Accuracy & Edit Distance & ed1 & Ch instances & Im Instances \\\\\n') 230 | for scr in scripts: 231 | correct_scr = correct_script[scr] 232 | correct_scr_ed1 = correct_ed1_script[scr] 233 | all = count_script[scr] 234 | ted_scr = ed_script[scr] 235 | gt_all_scr = gt_script[scr] 236 | print(' Script:{3} Acc : {0:.3f}, {1:.2f}, {2:.3f}, {4}'.format(correct_scr / float(max(all, 1)), ted_scr / 3.0, ted_scr / float(max(gt_all_scr, 1)), scr, gt_all_scr )) 237 | 238 | itf.write('{0} & {1:.3f} & {5:.3f} & {2:.3f} & {3} & {4} \\\\\n'.format( 239 | scr.title(), correct_scr / float(max(all, 1)), ted_scr / float(max(gt_all_scr, 1)), gt_all_scr, all, correct_scr_ed1 / float(max(all, 1)))) 240 | 241 | itf.write('{0} & {1:.3f} & {5:.3f} & {2:.3f} & {3} & {4} \\\\\n'.format( 242 | 'Total', correct / float(max(images_count, 1)), ted / float(max(gt_all, 1)), gt_all, images_count, correct_ed1 / float(max(images_count, 1)) )) 243 | itf.close() 244 | 245 | print(conf_matrix) 246 | np.savetxt("conf_matrix.csv", conf_matrix, delimiter=' & ', fmt='%d', newline=' \\\\\n') 247 | 248 | itf = open("conf_matrix_out.csv", "w") 249 | itf.write( ' & ' ) 250 | delim = "" 251 | for scr in scripts: 252 | itf.write( delim ) 253 | itf.write( scr.title() ) 254 | delim = " & " 255 | itf.write( '\\\\\n' ) 256 | 257 | script_no = 0 258 | with open("conf_matrix.csv", "r") as ins: 259 | for line in ins: 260 | line = scripts[script_no].title() + " & " + line 261 | itf.write(line) 262 | script_no +=1 263 | if script_no >= len(scripts): 264 | break 265 | 266 | fout.close() 267 | fout_ocr.close() 268 | net.train() 269 | 270 | pd.options.display.max_rows = 9999 271 | #pd.options.display.max_cols = 9999 272 | 273 | if len(bad_words) > 0: 274 | wworst = sorted(bad_words, key=lambda x: x[2]) 275 | 276 | ww = np.asarray(wworst, np.object) 277 | ww = ww[0:1500, :] 278 | df2 = pd.DataFrame({ 'gt' : ww[:, 0], 'pred' : ww[:, 1], 'ed' : ww[:, 2], 'image': ww[:, 3]}) 279 | 280 | html = df2.to_html(escape=False) 281 | report = open('{0}/ocr_bad.html'.format(dir_name), 'w') 282 | report.write(html) 283 | report.close() 284 | 285 | wworst = sorted(bad_words, key=lambda x: x[2], reverse=True) 286 | 287 | ww = np.asarray(wworst, np.object) 288 | ww = ww[0:1500, :] 289 | df2 = pd.DataFrame({ 'gt' : ww[:, 0], 'pred' : ww[:, 1], 'ed' : ww[:, 2], 'image': ww[:, 3]}) 290 | 291 | html = df2.to_html(escape=False) 292 | report = open('{0}/ocr_not_sobad.html'.format(dir_name), 'w') 293 | report.write(html) 294 | report.close() 295 | 296 | return correct / float(images_count), ted 297 | 298 | 299 | -------------------------------------------------------------------------------- /ocr_utils.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Oct 25, 2018 3 | 4 | @author: Michal.Busta at gmail.com 5 | ''' 6 | 7 | import math 8 | import numpy as np 9 | 10 | import torch 11 | import torch.nn.functional as F 12 | 13 | def print_seq_ext(wf, codec): 14 | prev = 0 15 | word = '' 16 | current_word = '' 17 | start_pos = 0 18 | end_pos = 0 19 | dec_splits = [] 20 | splits = [] 21 | hasLetter = False 22 | for cx in range(0, wf.shape[0]): 23 | c = wf[cx] 24 | if prev == c: 25 | if c > 2: 26 | end_pos = cx 27 | continue 28 | if c > 3 and c < (len(codec)+4): 29 | ordv = codec[c - 4] 30 | char = ordv 31 | if char == ' ' or char == '.' or char == ',' or char == ':': 32 | if hasLetter: 33 | if char != ' ': 34 | current_word += char 35 | splits.append(current_word) 36 | dec_splits.append(cx + 1) 37 | word += char 38 | current_word = '' 39 | else: 40 | hasLetter = True 41 | word += char 42 | current_word += char 43 | end_pos = cx 44 | elif c > 0: 45 | if hasLetter: 46 | dec_splits.append(cx + 1) 47 | word += ' ' 48 | end_pos = cx 49 | splits.append(current_word) 50 | current_word = '' 51 | 52 | 53 | if len(word) == 0: 54 | start_pos = cx 55 | prev = c 56 | 57 | dec_splits.append(end_pos + 1) 58 | conf2 = [start_pos, end_pos + 1] 59 | 60 | return word.strip(), np.array([conf2]), np.array([dec_splits]), splits 61 | 62 | def ocr_image(net, codec, im_data, detection): 63 | 64 | boxo = detection 65 | boxr = boxo[0:8].reshape(-1, 2) 66 | 67 | center = (boxr[0, :] + boxr[1, :] + boxr[2, :] + boxr[3, :]) / 4 68 | 69 | dw = boxr[2, :] - boxr[1, :] 70 | dh = boxr[1, :] - boxr[0, :] 71 | 72 | w = math.sqrt(dw[0] * dw[0] + dw[1] * dw[1]) 73 | h = math.sqrt(dh[0] * dh[0] + dh[1] * dh[1]) 74 | 75 | input_W = im_data.size(3) 76 | input_H = im_data.size(2) 77 | target_h = 40 78 | 79 | scale = target_h / max(1, h) 80 | target_gw = int(w * scale) + target_h 81 | target_gw = max(2, target_gw // 32) * 32 82 | 83 | xc = center[0] 84 | yc = center[1] 85 | w2 = w 86 | h2 = h 87 | 88 | angle = math.atan2((boxr[2][1] - boxr[1][1]), boxr[2][0] - boxr[1][0]) 89 | 90 | #show pooled image in image layer 91 | 92 | scalex = (w2 + h2) / input_W * 1.2 93 | scaley = h2 / input_H * 1.3 94 | 95 | th11 = scalex * math.cos(angle) 96 | th12 = -math.sin(angle) * scaley 97 | th13 = (2 * xc - input_W - 1) / (input_W - 1) #* torch.cos(angle_var) - (2 * yc - input_H - 1) / (input_H - 1) * torch.sin(angle_var) 98 | 99 | th21 = math.sin(angle) * scalex 100 | th22 = scaley * math.cos(angle) 101 | th23 = (2 * yc - input_H - 1) / (input_H - 1) #* torch.cos(angle_var) + (2 * xc - input_W - 1) / (input_W - 1) * torch.sin(angle_var) 102 | 103 | t = np.asarray([th11, th12, th13, th21, th22, th23], dtype=np.float) 104 | t = torch.from_numpy(t).type(torch.FloatTensor) 105 | t = t.cuda() 106 | theta = t.view(-1, 2, 3) 107 | 108 | grid = F.affine_grid(theta, torch.Size((1, 3, int(target_h), int(target_gw)))) 109 | 110 | 111 | x = F.grid_sample(im_data, grid) 112 | 113 | features = net.forward_features(x) 114 | labels_pred = net.forward_ocr(features) 115 | 116 | ctc_f = labels_pred.data.cpu().numpy() 117 | ctc_f = ctc_f.swapaxes(1, 2) 118 | 119 | labels = ctc_f.argmax(2) 120 | 121 | ind = np.unravel_index(labels, ctc_f.shape) 122 | conf = np.mean( np.exp(ctc_f[ind]) ) 123 | 124 | det_text, conf2, dec_s, splits = print_seq_ext(labels[0, :], codec) 125 | 126 | return det_text, conf2, dec_s -------------------------------------------------------------------------------- /sample_train_data/MLT/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Train Data Format 3 | 4 | code support 2 kind of annotations: 5 | - YOLO like format (https://github.com/MichalBusta/E2E-MLT/blob/3110671b178a868bc33c44442983170d57d6de89/data_gen.py#L39): 6 | 7 | ``` 8 | cls, x, y, w, h, angle, GT_TEXT 9 | ``` 10 | where: 11 | - cls is not used 12 | - [x, y] is center of bounding box (in relative coordinates: x = X / img.cols y = Y / img.rows ) 13 | - w, h is bounding box width and height normalized by image diagonal (w = W / sqrt( img.cols * img.cols + img.rows * img.rows)) 14 | - angle of rotated bounding box in radians 15 | 16 | - ICDAR like format (https://github.com/MichalBusta/E2E-MLT/blob/3110671b178a868bc33c44442983170d57d6de89/data_gen.py#L86): 17 | 18 | ``` 19 | x1,y1,x2,y2,x3,y3,x4,y4,GT_TEXT 20 | ``` 21 | where [x1,y1] is coordinate (in pixels) of bottom left corner of text bounding box. The bounding box is annoted in clock wise order (bottom left, top left, top right, top bottom). 22 | 23 | naming convetion is defined here: https://github.com/MichalBusta/E2E-MLT/blob/3110671b178a868bc33c44442983170d57d6de89/data_gen.py#L616 24 | -------------------------------------------------------------------------------- /sample_train_data/MLT/done/gt_img_5407.txt: -------------------------------------------------------------------------------- 1 | 910.992431640625,1273.0765380859375,1039.992431640625,1276.0765380859375,1024.507568359375,1941.9234619140625,895.507568359375,1938.9234619140625,1, 当社関係以外の 2 | 748.3333333333333,1266.4999999999998,875.3333333333333,1280.4999999999998,881.3333333333333,2052.5,764.3333333333333,2052.5,1, 駐車を御遠慮下さい 3 | 622.8502197265625,1639.7156982421875,626.1497802734375,1567.7843017578125,735.1497802734375,1572.7843017578125,731.8502197265625,1644.7156982421875,1, (株) 4 | 636.3333333333333,1680.4999999999998,717.3333333333333,1677.4999999999998,731.3333333333333,2005.4999999999998,650.3333333333333,2005.4999999999998,1, 新六商店 5 | -------------------------------------------------------------------------------- /sample_train_data/MLT/done/img_5407.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichalBusta/E2E-MLT/fc79f9ab4c8c75c882fae12c399d1c5355bb8a1b/sample_train_data/MLT/done/img_5407.jpg -------------------------------------------------------------------------------- /sample_train_data/MLT/icdar-2015-Ch4/Train/gt_img_784.txt: -------------------------------------------------------------------------------- 1 | 462,113,526,107,528,128,465,134,ARMANI 2 | 523,108,611,101,612,118,525,126,EXCHANGE 3 | 467,132,523,125,523,143,467,150,G-STAR 4 | 532,125,590,118,591,136,533,143,CALVIN 5 | 590,120,636,116,637,134,591,137,KLEIN 6 | 631,115,687,111,690,128,635,133,JEANS 7 | 467,151,521,145,522,160,468,167,BREAD 8 | 522,145,535,144,537,160,523,161,### 9 | 535,141,598,137,599,155,537,159,BUTTER 10 | 608,136,649,133,650,150,609,153,TRUE 11 | 649,132,723,125,724,143,650,150,### 12 | 391,158,417,155,418,174,392,176,B1 13 | 1,158,85,151,85,203,1,210,### 14 | 176,288,269,285,270,303,177,305,### 15 | 1041,181,1132,173,1140,243,1049,251,SALE 16 | -------------------------------------------------------------------------------- /sample_train_data/MLT/icdar-2015-Ch4/Train/img_784.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichalBusta/E2E-MLT/fc79f9ab4c8c75c882fae12c399d1c5355bb8a1b/sample_train_data/MLT/icdar-2015-Ch4/Train/img_784.jpg -------------------------------------------------------------------------------- /sample_train_data/MLT/trainMLT.txt: -------------------------------------------------------------------------------- 1 | done/img_5407.jpg 2 | icdar-2015-Ch4/Train/img_784.jpg 3 | -------------------------------------------------------------------------------- /sample_train_data/MLT_CROPS/gt.txt: -------------------------------------------------------------------------------- 1 | word_118.png, "Ngee" 2 | word_119.png, "Ann" 3 | word_120.png, "City" 4 | word_121.png, "ION" 5 | -------------------------------------------------------------------------------- /sample_train_data/MLT_CROPS/word_118.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichalBusta/E2E-MLT/fc79f9ab4c8c75c882fae12c399d1c5355bb8a1b/sample_train_data/MLT_CROPS/word_118.png -------------------------------------------------------------------------------- /sample_train_data/MLT_CROPS/word_119.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichalBusta/E2E-MLT/fc79f9ab4c8c75c882fae12c399d1c5355bb8a1b/sample_train_data/MLT_CROPS/word_119.png -------------------------------------------------------------------------------- /sample_train_data/MLT_CROPS/word_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichalBusta/E2E-MLT/fc79f9ab4c8c75c882fae12c399d1c5355bb8a1b/sample_train_data/MLT_CROPS/word_120.png -------------------------------------------------------------------------------- /sample_train_data/MLT_CROPS/word_121.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichalBusta/E2E-MLT/fc79f9ab4c8c75c882fae12c399d1c5355bb8a1b/sample_train_data/MLT_CROPS/word_121.png -------------------------------------------------------------------------------- /train_ocr.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Sep 29, 2017 3 | 4 | @author: Michal.Busta at gmail.com 5 | ''' 6 | import numpy as np 7 | import torch.nn as nn 8 | import torch.nn.functional as F 9 | 10 | import os 11 | 12 | f = open('codec.txt', 'r') 13 | codec = f.readlines()[0] 14 | f.close() 15 | print(len(codec)) 16 | 17 | import torch 18 | import net_utils 19 | import argparse 20 | 21 | import ocr_gen 22 | 23 | from warpctc_pytorch import CTCLoss 24 | from torch.autograd import Variable 25 | 26 | from models import ModelResNetSep2 27 | from ocr_test_utils import print_seq_ext 28 | import random 29 | 30 | import cv2 31 | 32 | 33 | base_lr = 0.0001 34 | lr_decay = 0.99 35 | momentum = 0.9 36 | weight_decay = 0.0005 37 | batch_per_epoch = 5000 38 | disp_interval = 500 39 | 40 | 41 | def main(opts): 42 | 43 | model_name = 'E2E' 44 | net = ModelResNetSep2(attention=True) 45 | acc = [] 46 | 47 | if opts.cuda: 48 | net.cuda() 49 | 50 | optimizer = torch.optim.Adam(net.parameters(), lr=base_lr, weight_decay=weight_decay) 51 | step_start = 0 52 | if os.path.exists(opts.model): 53 | print('loading model from %s' % args.model) 54 | step_start, learning_rate = net_utils.load_net(args.model, net, optimizer) 55 | else: 56 | learning_rate = base_lr 57 | 58 | step_start = 0 59 | 60 | net.train() 61 | 62 | #acc_test = test(net, codec, opts, list_file=opts.valid_list, norm_height=opts.norm_height) 63 | #acc.append([0, acc_test]) 64 | 65 | ctc_loss = CTCLoss() 66 | 67 | data_generator = ocr_gen.get_batch(num_workers=opts.num_readers, 68 | batch_size=opts.batch_size, 69 | train_list=opts.train_list, in_train=True, norm_height=opts.norm_height, rgb = True) 70 | 71 | train_loss = 0 72 | cnt = 0 73 | 74 | for step in range(step_start, 300000): 75 | # batch 76 | images, labels, label_length = next(data_generator) 77 | im_data = net_utils.np_to_variable(images, is_cuda=opts.cuda).permute(0, 3, 1, 2) 78 | features = net.forward_features(im_data) 79 | labels_pred = net.forward_ocr(features) 80 | 81 | # backward 82 | ''' 83 | acts: Tensor of (seqLength x batch x outputDim) containing output from network 84 | labels: 1 dimensional Tensor containing all the targets of the batch in one sequence 85 | act_lens: Tensor of size (batch) containing size of each output sequence from the network 86 | act_lens: Tensor of (batch) containing label length of each example 87 | ''' 88 | 89 | probs_sizes = torch.IntTensor( [(labels_pred.permute(2,0,1).size()[0])] * (labels_pred.permute(2,0,1).size()[1]) ) 90 | label_sizes = torch.IntTensor( torch.from_numpy(np.array(label_length)).int() ) 91 | labels = torch.IntTensor( torch.from_numpy(np.array(labels)).int() ) 92 | loss = ctc_loss(labels_pred.permute(2,0,1), labels, probs_sizes, label_sizes) / im_data.size(0) # change 1.9. 93 | optimizer.zero_grad() 94 | loss.backward() 95 | optimizer.step() 96 | if not np.isinf(loss.data.cpu().numpy()): 97 | train_loss += loss.data.cpu().numpy()[0] #net.bbox_loss.data.cpu().numpy()[0] 98 | cnt += 1 99 | 100 | if opts.debug: 101 | dbg = labels_pred.data.cpu().numpy() 102 | ctc_f = dbg.swapaxes(1, 2) 103 | labels = ctc_f.argmax(2) 104 | det_text, conf, dec_s = print_seq_ext(labels[0, :], codec) 105 | 106 | print('{0} \t'.format(det_text)) 107 | 108 | 109 | 110 | if step % disp_interval == 0: 111 | 112 | train_loss /= cnt 113 | print('epoch %d[%d], loss: %.3f, lr: %.5f ' % ( 114 | step / batch_per_epoch, step, train_loss, learning_rate)) 115 | 116 | train_loss = 0 117 | cnt = 0 118 | 119 | if step > step_start and (step % batch_per_epoch == 0): 120 | save_name = os.path.join(opts.save_path, '{}_{}.h5'.format(model_name, step)) 121 | state = {'step': step, 122 | 'learning_rate': learning_rate, 123 | 'state_dict': net.state_dict(), 124 | 'optimizer': optimizer.state_dict()} 125 | torch.save(state, save_name) 126 | print('save model: {}'.format(save_name)) 127 | 128 | #acc_test, ted = test(net, codec, opts, list_file=opts.valid_list, norm_height=opts.norm_height) 129 | #acc.append([0, acc_test, ted]) 130 | np.savez('train_acc_{0}'.format(model_name), acc=acc) 131 | 132 | if __name__ == '__main__': 133 | parser = argparse.ArgumentParser() 134 | 135 | parser.add_argument('-train_list', default='/home/busta/data/90kDICT32px/train_mlt.txt') 136 | parser.add_argument('-valid_list', default='/home/busta/data/icdar_ch8_validation/ocr_valid.txt') 137 | parser.add_argument('-save_path', default='backup2') 138 | parser.add_argument('-model', default='/mnt/textspotter/tmp/DS_CVPR/backup2/ModelResNetSep2_25000.h5') 139 | parser.add_argument('-debug', type=int, default=0) 140 | parser.add_argument('-batch_size', type=int, default=4) 141 | parser.add_argument('-num_readers', type=int, default=1) 142 | parser.add_argument('-cuda', type=bool, default=True) 143 | parser.add_argument('-norm_height', type=int, default=40) 144 | 145 | args = parser.parse_args() 146 | main(args) 147 | 148 | --------------------------------------------------------------------------------