福野泰介の一日一創 - create every day

見る人すべてがめがねをかけて見える「meganeworld
MR(Mixed Reality)による近未来、たった800円のスマホVRで開発可能です。

見えている人が「かわいい」と、人はやさしくなれるかも?

安直な「かわいい」の実現「ネコミミ」を見ている人側で勝手に付加するMRアプリを作ってみましょう。

Hana道場、若宮さんと学ぶIoTとIchigoJamプログラミングと地域フィールドラボ第5期スタート!」より

GitHubにあるiPhone用、プログラミング言語Swiftで書かれた、「meganeworld - megane」 にネコミミ表示を足します。 右目位置、左目位置を、顔認識APIから受け取って、三角関数を使って角度を求め、ネコミミ位置を計算し、黒の三角形を描画!(プログラム全文はGitHubで

// nekomimi let dx = left.x - right.x let dy = left.y - right.y let len = sqrt(dx * dx + dy * dy) let th = atan2(dy, dx); let ox = [ right.x, left.x ] let oy = [ right.y, left.y ] for n in 0...1 { let dir = CGFloat(n == 0 ? 1 : -1) let deg0 = 90 + 20 * dir let th0 = th + CGFloat.pi / 180 * CGFloat(deg0) let len0 = len * 1.3 let x0 = ox[n] + cos(th0) * len0 let y0 = oy[n] + sin(th0) * len0 g.beginPath() g.setLineWidth(4) g.setFillColor(UIColor.white.cgColor) let th1 = th0 + CGFloat.pi / 180 * 20 * dir let len1 = len * 0.4 let x1 = x0 + cos(th1) * len1 let y1 = y0 + sin(th1) * len1 g.move(to:CGPoint(x:x1, y:y1)) let th2 = th1 + CGFloat.pi / 180 * 120 * dir let len2 = len * 0.6 let x2 = x0 + cos(th2) * len2 let y2 = y0 + sin(th2) * len2 g.addLine(to:CGPoint(x:x2, y:y2)) let th3 = th1 - CGFloat.pi / 180 * 120 * dir let len3 = len * 0.6 let x3 = x0 + cos(th3) * len3 let y3 = y0 + sin(th3) * len3 g.addLine(to:CGPoint(x:x3, y:y3)) g.addLine(to:CGPoint(x:x1, y:y1)) g.fillPath() }

MSX BASICの三角関数であれこれ遊んだ小中学生時代。
シューティングゲームや、優雅な動き、3Dプログラミングなど、よく出てくるので遊びながら覚えちゃいます。
一番好きな三角関数は、atan2こと、yとxをパラメータとして渡す逆タンジェント(Arctangent)
atan(y / x) として使うため、引数の順序も普通じゃない atan2(y, x) というのもお気に入り。

Swiftでプログラミングしていて驚いたコンパイルエラー
「Expression was too complex to be solved in reasonable time; ...」
IchigoJamのも計算用のスタックに多くのメモリを使えないため「Too complex」というエラーがありますが、現代言語でも目にかかるとは!

IchigoJamと同様、式を分割するか、型の明確化で対応が可能しましょう。

links
- Ichigojam Basicで円を描く – chobitte
- 2015-08-26 [IchigoJam]円を描く - SHIROのモバイル日記
- 三角関数が好き sin cos tan

学生の頃、たくさん遊びましたが、安価で多様なITおもちゃが無数にある現代の学生は更に遊び放題でうらやましい!

お金になるならない、役に立つ立たない、受ける受けない、そんなこと一切気にしなくていいのが遊びのいいところ。 思うがままに作ったら、誰かに見せる遊びもしてみましょう。きっと世界が広がります!

遊び場と遊ぶルールに制限なし。多少の無茶が効く学生のうちに可能性と多様性をめいいっぱい広げておくと、後々きっと便利です。

ということで、福井近辺に住んでいる学生にオススメ「学生団体with
次なる遊びの企み会議にお邪魔してプレゼントしてきた、100均VR!


なんと100均のお店、セリアにダンボールを使った組み立てカンタン「VRゴーグル」が売ってました!


レンズが2つついて、しっかり3Dで見え、ハサミを入れればWebMegane用MRゴーグルが完成。 バンドは付属しないので、何か適当なものを追加で買ってきてオリジナルデジタルメガネづくりを楽しみましょう! スマホを固定することができないので、滑り落ち防止用の何か改造も必要に応じてどうぞ。


見えないものが見えるのが楽しい、WebMegane。電脳メガネアプリ「colorsight」に、色の名前を表示機能を追加してみました。 和名の色名一覧オープンデータを作って、組み合わせると、ステキな色の名前に出会えそう。
色名一覧 - Wikipedia


ひさびさに100均、セリアに行くと、スマホグッズが充実してました!
いろいろ組み合わせて楽しく遊んでしまいましょう!

2018年、jig.jp 高専インターンのメンバーが決定しました。
今年の鯖江の夏も、大いに盛り上がりそうです。
応募してくれた学生さん、ありがとうございます!
残念ながら落選してしまった方、ごめんなさい。よかったら、またチャレンジしてください。

楽しみは創れる!

links
- WebMegane - your new digital sight / デジタルな視界 on iPhone Safari x VR goggles
- taisukef/WebMegane: Megane (eye-glasses) by WebMR - GitHub
- 電脳コイル|磯光雄監督作品

2次元のテレビやスマホでは伝わらない、VR/AR/MRのスゴさ。実際体験するしかないですねっ。

アメコミ化しためがね大使まゆちゃん。視界がリアルタイムに変換されて、アメコミの世界にいった感覚になれます。・・・と、いくら書いても伝わらないのがもどかしいところ。(アメコミメガネ on スマホVR


めがねフェスでも人気だった、Oculus Go。 自分で創りたくなるのがものづくり好きの性。シンプルながら操作性抜群の Oculus Go controller をwebアプリで取得する方法を調査。 無事、ボタンと加速度の値が取れました!

const gp = navigator.getGamepads()[0]; const corient = gp.pose.orientation; const pad = gp.buttons[0].pressed; const trigger = gp..buttons[1].pressed;

方向とトリガー、パッド部分が押されたかどうかが取得できます。(戻るキーはVRモードが終了してしまう)
* VRDisplay requestPresent した後のみ有効です


視点移動と合わせたシンプルなサンプルとしてまとめて公開したいと思います。


MRの不思議な世界、お子様たちも興味津々。ようこそプログラマブルワールドへ。


まゆちゃんも体験!


NUAGEのメガネアイス!


NUAGEは、めがねグルメグランプリ、二冠!


次回のめがねフェスではどこまで進化しているか!?


めがね大使まゆちゃんとめがね会館 in アメコミ世界

links
- Oculus Go | Oculus (スマホVRの一段上質のVR体験が23,800円!)

めがねのあなたを産地は待っている!めがねフェス2018、開幕です

めがねとの出会い。メガネな求人コーナー。(めがね会館で働く、ITな求人も


めがねよ、ありがとう作文。めがねが良くしてくれるのは目だけじゃない。


メガネ屋さんと直接話せる、ポップアップギャラリーも大賑わい。メガネ好き集まってます!


巨大、めがねフェス!撮影スポットとして活躍


Hana道場の高校生が開発、めがねフェス合成コーナー。
neoplug体験コーナーもある「めがねxIT」コーナーはその向かい、めがね会館駐車場にて。


増永さんも気に入った!Oculus Go。鯖江のメガネ産業は未来も見てます。


さり気なくHana道場を宣伝する、六足歩行ロボFOLO
VRも、電脳メガネも、ロボットも、洗濯機だって、コンピューター。プログラミングで動いてます。
IchigoJamは、誰にでもやさしい、プログラミングへの入り口を提供中。興味持ったら、Hana道場


ロボットプログラミングに挑戦してくれた4歳児。はじめてのキーボード、気に入った様子。


ロボットはコンピューター。プログラミングで思い通りに動かせます。(接続かんたん、解説は末尾に!)


みんなめがねをかけちゃうメガネワールドメガネ。モデル:梵、加藤さん!


アメコミ風に見えるメガネ


めがね会館を見上げるとまがまがしくておもしろい。


めがね会館内では、美容健康コーナー。ルテインを計測する鯖江市長。
目にもおいしい食事オープンデータ、良さそうですね!


鯖江市から国連大使へ、SDGsスペシャルなメガネ、プレゼント!? SDGs special eyeglasses


鯖江は、国連サミットで採択された「SDGs」に取り組み、持続可能な地域モデル「めがねのまちさばえへ」。 Think Globally! Act Locally! 世界視野で、地域で行動する。外国の方、県外の方にもやさしい町、創りましょう。


毎年好評、メガリンピック


ステージイベント、めがね大使、Cutie Pai まゆちゃん


人気スイーツ、メガネマフィン


福井と言えば、日本酒。フルーツあまざけ、酒粕アイスキャンディーはお子様でも、車でも大丈夫。


ボルガライスなどご当地グルメも揃ったフードコーナー。レギュレーションは、メガネです。


メガネ好きならいろいろ楽しい、めがねフェス。今年で5年目!


東京、大阪、名古屋からもたくさん!Youはどこからきたの?Day1夕方時点


鯖江駅から徒歩10分、めがね会館(めがねミュージアム)を目印にどうぞ!


めがねフェス。6/10 日曜日、16時まで!

FOLOとMapleSyrupのつなぎ方。

1. IchigoJam Tと慎重に合体させる *Uや初代でもMapleSyrup説明書に接続方法記載!
2. FOLOの電池ボックスの赤黒をCN5の一番上(赤)と一番下(黒)へつなぐ
3. FOLOの前後歩き用モーター青黒を、青と緑のジャンパー線でOUT1,2へ
4. FOLOの旋回用モーター黒赤を、白とオレンジのジャンパー線でOUT3,4へ


あとはプログラミング!
OUT1 で前進、OUT2 で後退。
OUT16 で右旋回、OUT32 で左旋回
待つコマンド WAIT60 や、最初から繰り返す GOTO10 コマンドと組み合わせて、自由自在!


モーター2つをかんたん制御、こどもモーターボード、メープルシロップ(MaypleSyrup)
その他、おすすめ商品が揃う「ショップ一日一創」もオープン!

links
- 改造してプログラミングも楽しい!4千円6足歩行ロボ「FOLO」の組み立てとIchigoJamコントロール

Welcome to Megane World! めがねをかけないと損する時代は、もうまもなく!

一足先にスマホMRで体験、見えている人、全員が赤いメガネをかける世界。


6/9-10の2日間はステキなメガネに会える「めがねフェス2018
ステージ、グルメ、ショップ、ワークショップなど、イベント盛りだくさん!隣のめがね会館へもどうぞ!


オススメは800円から買えちゃう、各種スマホVR、ぜひ試着してお気に入りのVRを手に入れてください。
一段上のVR体験、Oculus Go も展示!
発売開始から3分で完売 Oculus Go中国国内モデル、入荷待ちは5万人以上 | Mogura VR - 国内外のVR/AR/MR最新情報


めがねxIT」ブースで体験できるメガネアプリ開発者は鯖江在住の現役高校生プログラマー!
ITの基本、プログラミングを子供も大人も学べる格安パソコン「IchigoJam」の体験コーナーもあります。限定品の販売も!?


めがねのまちさばえ!

links
- めがねフェス2018

昨年のVRフレンズ2に続き、VRな会社、フォーラムエイトさん提供のパックンの対談番組「Innovative Tomorrow ~VRが変えるあの業界の未来!~」の収録。 エンジニアなら誰もが憧れるVR、MRの世界。スマホと安いのゴーグル(1000円)があれば、意外と手軽に未来にいけます。


さすがパックン、アメコミ調が似合う!

おみやげに持っていった、iPhoneのフィルタ CIComicEffect を使いリアルタイムに視界をプログラミングで書き換える、デジタルメガネ。 探す時代から、見える時代へ。まずは外観と持続時間をがまんすれば、実用レベル。(src on GitHub)

let filter = CIFilter(name: "CIComicEffect") filter.setValue(CIImage(image: image), forKey: kCIInputImageKey) image = UIImage(ciImage: filter.outputImage!)

iOS標準のライブラリ(ソフトウェアの部品のこと)を使うだけなので、実現するプログラムもとってもシンプル!


THETAで360度撮影。空気感のそのまま保存、もう1段画質が上がってくれるとステキです。


「Innovative Tomorrow ~VRが変えるあの業界の未来!~」
(放送日は 2018.7.2(火) 0:00-0:30 でした)

メガネのまち鯖江なので、デジタルメガネも鯖江から!
夏のインターンのネタにもいいかも。応募締切は今週末。興味ある学生、奮って応募ください!
高専インターン募集開始!鯖江を鯖江でハックしよう / バスのスピードメーターアプリ

WebMegane、今いる場所と見ている方角が分かれば、現実にいろいろ情報が加えられます。
JSで方位を取得する deviceorientation を使ってみるも、どうも値が安定しない・・・。

compass」 参考:DeviceOrientation Event Specification - W3C

手元のiPhone X、北がずれたり、南と逆になったりちょっとよく分からない動作をしてますが、とりあえず、WebMegane colorsight にも組み込んでみました。 標準アプリのコンパスとのズレがなくなるような取得方法、何か別にあるのかも??(window.devicePixelRatio を使ったRetinaにちゃんと対応、スマホMRの画質も圧倒的にアップしました!)


良い天気に恵まれた地区の運動会!今回は綱引きに出場。


空き時間のテントでデモするIchigoSodaのIoT。安さがイノベーション、いろんな分野で使える、IoT!

二次元では伝わらないVR/MR。THETAで撮影した運動会・打ち上げの雰囲気をスマホVRで体験してもらう良い機会。

望遠ズームの一眼レフでとらえた町内の勇姿、スマホVRで大きくきれいに見るアプリを作るのは良さそう。

いろんな人、いろんなスマホが集う町内会、プラスITで、もっと楽しい!

Code for Sabae発、WebMeganeがCode for Nerimaに飛び火。
WebMegane(色覚体験)

WebMegane、色を文字化してみました。

colorsightsrc on GitHub in JS
時計表示のおまけ付き! 簡単なJavaScriptで改造可能です!


マダガスカル、モロッコからの留学生へIchigoSodaレクチャーする高専生!


夜は高専インターンOG/OBと!

高専生による高専生のための、最高のインターンを目指す、jig.jpインターン、申込み期限間近!
学生インターンプログラム2018~全国高専生向けjig.jpインターンシップ募集開始のお知らせ~

外カメラ x スマホVR = デジタルメガネ

JSで手軽なWebMeganeもオススメながら、iPhoneネイティブアプリとして作ると、顔認識や、QRコード認識などが高速で楽しい!

リアルタイムにQRコード内容をデコードして、視界をオーバーレイ(上書き)するメガネができた。
megane - qrdetector on GitHub」 Swift4で実装

ウィンクシャッターが便利だったGoogle Glassのように、手軽に写真撮影もついでに実装。
ボリュームダウンキーで、シャッター(初回のみダイアログがでるので、VRにする前に押しておこう)
ボリュームアップキーで、視界をズームすることもできる(現在は、1920x1080の画像をデジタルズーム)

こちら「オタマートで売ってるVRゴーグル」の一番安いもの。ボリュームアップダウンが上からアクセスできる!
ボリュームアップダウンキーのついたイヤホンを接続すると、手元でも操作できるようになって便利。
デジタルメガネなUXづくり、いろいろ試していきましょう。

鯖江の道の駅、西山公園前のバス停。日本語表記しかない標識にQRコードをつけておけば、リアルタイムに見ている人の母国語に変換できそう。

Let's hack your sight!

AppDelegate.swift

import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { return true } func applicationWillResignActive(_ application: UIApplication) { } func applicationDidEnterBackground(_ application: UIApplication) { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "applicationDidEnterBackground"), object: nil) } func applicationWillEnterForeground(_ application: UIApplication) { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "applicationWillEnterForeground"), object: nil) } func applicationDidBecomeActive(_ application: UIApplication) { } func applicationWillTerminate(_ application: UIApplication) { } }

ViewController.swift

// // ViewController.swift // megane, QR code detector glass with VR goggle // // CC BY taisukef on 2018/05/24. // http://fukuno.jig.jp/2133 // import UIKit import AVFoundation import MediaPlayer class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.black self.imageView1 = UIImageView() self.imageView2 = UIImageView() let w = self.view.frame.width let h = self.view.frame.height let w2 = w / 2 let h2 = w2 * 1080 / 1920 let y = (h - h2) / 2 self.imageView1.frame = CGRect(x:0, y:y, width:w2, height:h2) self.imageView2.frame = CGRect(x:self.view.frame.width / 2, y:y, width:w2, height:h2) self.view.addSubview(self.imageView1) self.view.addSubview(self.imageView2) self.initNotificationsFromAppDelegate() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } var input:AVCaptureDeviceInput! var output:AVCaptureVideoDataOutput! var session:AVCaptureSession! var camera:AVCaptureDevice! var imageView1:UIImageView! var imageView2:UIImageView! override func viewWillAppear(_ animated: Bool) { self.configureCamera() self.listenVolumeButton() } // notifications foreground and background func initNotificationsFromAppDelegate() { NotificationCenter.default.addObserver(self, selector: #selector(type(of: self).viewWillEnterForeground(notification:)), name: NSNotification.Name(rawValue: "applicationWillEnterForeground"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(type(of: self).viewDidEnterBackground(notification:)), name: NSNotification.Name(rawValue: "applicationDidEnterBackground"), object: nil) } @objc func viewWillEnterForeground(notification: NSNotification?) { print("foreground") self.listenVolumeButton() } @objc func viewDidEnterBackground(notification: NSNotification?) { print("background") self.removeVolumeButton() } // override func viewDidDisappear(_ animated: Bool) { session.stopRunning() for output in session.outputs { session.removeOutput(output) } for input in session.inputs { session.removeInput(input) } session = nil camera = nil } let DETECT_QRCODE = false func configureCamera() { session = AVCaptureSession() // iPhone Xで実験 //session.sessionPreset = AVCaptureSession.Preset.cif352x288 // 34% 荒い //session.sessionPreset = AVCaptureSession.Preset.vga640x480 // 47% 4:3 なかなかきれい //session.sessionPreset = AVCaptureSession.Preset.iFrame1280x720 // CPU50% 16:9 かわらない? //session.sessionPreset = AVCaptureSession.Preset.hd1280x720 // CPU50% 16:9 きれい session.sessionPreset = AVCaptureSession.Preset.hd1920x1080 // CPU88% 16:9 かわらない? iPhone6でもQRcode offならOK! //session.sessionPreset = AVCaptureSession.Preset.hd4K3840x2160 // CPU93% 16:9 かわらない? QRcode offなら実用的 camera = AVCaptureDevice.default( AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType.video, position: .back) // position: .front do { input = try AVCaptureDeviceInput(device: camera) } catch let error as NSError { print(error) } if (session.canAddInput(input)) { session.addInput(input) } output = AVCaptureVideoDataOutput() // AVCapturePhotoOutput() 写真用 output?.videoSettings = [kCVPixelBufferPixelFormatTypeKey as AnyHashable : Int(kCVPixelFormatType_32BGRA)] as! [String : Any] let queue:DispatchQueue = DispatchQueue(label: "myqueue", attributes: .concurrent) output.setSampleBufferDelegate(self, queue: queue) output.alwaysDiscardsLateVideoFrames = true // 間に合わないものは処理しない if (session.canAddOutput(output)) { session.addOutput(output) } session.startRunning() } var zoom:CGFloat = 1.0 func captureOutput(_: AVCaptureOutput, didOutput: CMSampleBuffer, from: AVCaptureConnection) { // from.videoOrientation = .portrait //デバイスの向きを設定、縦の時 from.videoOrientation = .landscapeLeft //デバイスの向きを設定、landscape left の時 DispatchQueue.main.sync(execute: { var image = self.imageFromSampleBuffer(sampleBuffer: didOutput) image = resizeImage(image: image, ratio: zoom) if DETECT_QRCODE { image = drawQR(image: image) } self.imageView1.image = image self.imageView2.image = image }) } func resizeImage(image: UIImage, ratio: CGFloat) -> UIImage { if ratio == 1.0 { return image } let iw = image.size.width / ratio let ih = image.size.height / ratio let size = CGSize(width: iw, height: ih) UIGraphicsBeginImageContext(size) image.draw(in: CGRect(origin: CGPoint(x:-(image.size.width - iw) / 2, y:-(image.size.height - ih) / 2), size: image.size)) let resimage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return resimage } func drawQR(image: UIImage) -> UIImage { UIGraphicsBeginImageContext(image.size) let rect = CGRect(x:0, y:0, width:image.size.width, height:image.size.height) image.draw(in: rect) let g = UIGraphicsGetCurrentContext()! g.setStrokeColor(UIColor.white.cgColor) g.setLineWidth(1) let font = UIFont.boldSystemFont(ofSize: 14) let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle let textFontAttributes = [ NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: UIColor.black, NSAttributedStringKey.paragraphStyle: textStyle ] // 顔認識もおもしろい // let detector : CIDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options:[CIDetectorAccuracy: CIDetectorAccuracyLow] )! // 読める四角は今のところひとつだけ // let detector : CIDetector = CIDetector(ofType: CIDetectorTypeRectangle, context: nil, options:[CIDetectorAccuracy: CIDetectorAccuracyHigh, CIDetectorAspectRatio: 1.0] )! let detector : CIDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options:[CIDetectorAccuracy: CIDetectorAccuracyHigh] )! let features : NSArray = detector.features(in: CIImage(image: image)!) as NSArray if features.count > 0 { for feature in features as! [CIQRCodeFeature] { var rect: CGRect = (feature as AnyObject).bounds rect.origin.y = image.size.height - rect.origin.y - rect.size.height // QRコードを上書き! g.beginPath() g.setFillColor(UIColor.white.cgColor) g.addRect(rect) g.fillPath() feature.messageString?.draw(in: rect, withAttributes: textFontAttributes) } } let resimage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return resimage! } func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> UIImage { let imageBuffer: CVImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0)) let baseAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0) let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer) let width = CVPixelBufferGetWidth(imageBuffer) let height = CVPixelBufferGetHeight(imageBuffer) let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = (CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) let context = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) let imageRef = context!.makeImage() CVPixelBufferUnlockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0)) return UIImage(cgImage: imageRef!) } // volume switch var initialVolume = 0.0 var volumeView: MPVolumeView? func listenVolumeButton() { volumeView = MPVolumeView(frame: CGRect(x:-3000, y:0, width:0, height:0)) view.addSubview(volumeView!) let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setActive(true) let vol = audioSession.outputVolume initialVolume = Double(vol.description)! if initialVolume > 0.9 { initialVolume = 0.9 } else if initialVolume < 0.1 { initialVolume = 0.1 } } catch { print("error: \(error)") } audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil) } func removeVolumeButton() { AVAudioSession.sharedInstance().removeObserver(self, forKeyPath: "outputVolume") volumeView?.removeFromSuperview() } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "outputVolume" { let volume = (change?[NSKeyValueChangeKey.newKey] as! NSNumber).floatValue let newVolume = Double(volume) if newVolume > initialVolume + 0.05 { if let view = volumeView?.subviews.first as? UISlider { // volume up pressed view.value = Float(initialVolume) if zoom < 12.0 { zoom *= 1.2 } else { zoom = 1.0 } print("zoom: \(zoom)") } } else if newVolume < initialVolume - 0.05 { if let view = volumeView?.subviews.first as? UISlider { // volume down pressed view.value = Float(initialVolume) /* if zoom > 1.0 { zoom /= 1.2 } */ if let image = self.imageView1.image { saveImage(image: image) print("save image") } } } } } // save private func saveImage(image: UIImage) { UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil) } }

megane - qrdetector on GitHub」 in Swift4

links
- WebMegane - your new digital sight / デジタルな視界 on iPhone Safari x VR goggles (JS、webアプリ版)

鯖江市内を中心に1846の会員を持つ、鯖江商工会議所の記念すべき第60回通常議員総会。

WebMegane」 JSで作ったブラウザで動くWebMeganeに、反転モードを追加
左右反転させるレンズもプログラム1行で実現できてしまう、デジタル化したメガネ。

強烈に気持ち悪い左右反転視界も、しばらく歩き回っているとなんとかなってしまう不思議。
電話も、ネットも、スマホ、「今までの常識と違う」気持ち悪さも「利便性」には叶わない。

一眼レフがデジタル化し、光学ファインダーから液晶モニター化によるミラーレスが実現したように。 メガネの世界でもレンズレス時代が訪れる。


今までの延長線上じゃだめだと開会宣言する、鯖江商工会議所、黒田会頭。


新任で阪大から来られた福井工業大学、学長で、理学博士の掛下知行さんと鯖江市長!
商工会議所、鯖江市、福井工大による産官学連携も丸10年。


鯖江商工会議所副会頭「」代表の加藤さんによる〆。


サイトリニューアルしていた「日本酒「梵」の酒蔵 | 加藤吉平商店 |


SDGsバッジとメガネバッジを付けた鯖江市長、いよいよ国連本部、ニューヨークへ!
鯖江の市長さん、ニューヨークへ行く!こどもプログラミングで地方が変わる、EDIX&自治体総合フェア!
鯖江の新しい一歩のきっかけに!

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY 福野泰介 - Taisuke Fukuno / @taisukef / アイコン画像 / プロフィール画像