電算倶楽部 富山県のコンピュータ社会人サークル

富山県、特に滑川市、富山市、魚津市周辺で活動している社会人サークルです。

ホワイトボードアプリで疑似テレワーク

はじめに

東京オリンピック開催に加えコロナウイルスの流行が起こり、幸か不幸かテレワークの普及に拍車がかかりました。 パソコン持ち出して一人で作業するのもいいですが、様々なITツールを使えば職場にいるときと同じような(場合によってはそれ以上に)仕事ができるようになる、気がします。会社で禁止されているので使ったことがないんでわからないんですけどね。

まずは仲間内でひっそり使ってみてみたので感想をまとめます。

ホワイトボード

Zoom

今回は4人、オンライン会議システムのZoomで話をしたのですが、Zoomにもホワイトボード機能がついています。 ちょっとした共有ならば、Zoom会議中にサクッと立ち上げられるので便利。 機能はそんなに多くなさそうかな。

miro

https://miro.com/

見ろ。

図形描画ソフト。共有ホワイトボードとして使える。 ログインなしの場合は閲覧のみ。ログインすることで共同編集できる。

Slackアカウントでログイン可能のため、Slack利用グループは敷居が低い。

Windows10,Android(iOSも?)アプリ有り。 アプリだと幾分か動作が軽快。 でも、なぜかアプリだとSlackアカウントが使えない…

ホワイトボードだけにとどまらず、マインドマップフローチャートといった「ちゃんとした」図も作れる。 それも、1から作るわけではなくテンプレートが用意されているので、みんなで素早く作って素早く共有できる。

その分操作が複雑かつ画面の広さが必要で、PCを使ったほうが良さそう。 今回はアプリ未導入のスマホユーザが多かったのであまり良い反応がもらえなかった。

無料版の制約:

  • ボード3つまで
  • チームへの招待は不可

Sketchboard

https://sketchboard.me/

こちらも高機能。ヘタウマ系のテンプレおおい。 miroの影に隠れちゃっているような。

無料版の制約: - 5ユーザまで

Microsoft Whiteboard

https://wbd.ms/

マイクロソフト製。Windows10を始め、iOS用にアプリがある(Androidは?:anger:) Webでも使えるらしい1ため、アプリを入れられない場合でも大丈夫なはず。 Microsoftアカウントが必要になる。

操作感は本物のホワイトボードに近い。ペンの種類が豊富。動作は軽快。 ワードやパワーポイントのファイルを埋め込めるみたい。テンプレも多いです。 図形は苦手かな?

Google Jamboard

https://jamboard.google.com/

シンプルなホワイトボード。 主催者がボードを作成してゲスト招待。ゲストはログイン不要。 難しいものなんていらない、これでいいじゃん。

ゲストユーザは動物名がつけられる。動物園状態。 吠えて鳴くばかりで進捗がない、会社の会議への皮肉でしょうか。

別途販売している物理ホワイトボードと連動が可能。お高いので誰かお金ください。

Office

ホワイトボードではないですが有用そうなので紹介します。

Google Spreadsheet

https://docs.google.com/spreadsheets/

GoogleExcel。 ログインしなくても編集できるよう権限設定できる。 Excel使い慣れているならば特に説明する必要のない。手軽。

Excelのオンライン版もあるが、Office 365の契約が必要。

Android, iOSアプリ有り。

こちらも動物園化する。

終わりに

ガッツリビジネスで使うのであればMiro、 Zoomから手軽に使うのであればZoomのホワイトボード、 Zoomでなくて手軽に使うのであればGoogle Jamboardがいいかな、と感じました。 会社がクラウドサービスを許すのであれば是非活用してみてください。


  1. ログイン画面はあるのだけど、みんなログインできなかった。

Tileレビュー

キャッシュレスの流れで小さい財布にしたのですが、その分なくしやすくなってしまいました。 そこで、無くしもの防止のためにTileというキーホルダーサイズのチップを買ってみましたので紹介します。 売値は2,000円弱ですが、たまたま1,000円ちょっとで売っていましたので、財布用に加え鍵用に2つ購入しました。

thetileapp.jp

f:id:s-densan:20200326215536j:plain
Tile1

あらかじめスマホBluetoothでペアリングしておきます。 Bluetooth接続状態なら、スマホアプリから操作をすると音がなります。 逆に、Tileのボタンを押すとスマホから音がなります(こっちのほうがよく使いそう)。

Bluetoothと接続されていなくても、最後に接続できた場所を確認できます。 車につければ駐車場所を確認するのにも使えそうです。

欠点は、電池の残量がわからないこと。大体1年で切れるらしいです。 アプリとリンクした日はわかるのですが、そうしょっちゅう確認しないので気がついたらなくなっていたということになりそうです。 そういうわけで、直近の電池交換日をテプラで貼ってみました。目につくので忘れないはず。

f:id:s-densan:20200326215540j:plain
Tile2

ついでに電池の型式も書いておきました。

学習サイトを調べる

はじめに

たまたま図書館に行ったときに、gaccoのチラシが置いてありました。 「誰でも使える統計オープンデータ」という講義の紹介で、ちょうど統計を勉強したいと思っていたので自宅で調べてみました。

日本オープンオンライン教育推進協議会と、ドコモgacco株式会社が作ったという、ウェブ学習サイト。 いわゆるeラーニングを受けられるサービスのようです。無料講座もたくさんあるみたいです。

せっかくなので、gacco以外にもウェブ学習サイトについて、コンピュータ関係を中心にどのようなものがあるか調べてみました。

登録してみたサービス

gacco

https://gacco.org/

大学教授をはじめとした一流の講師陣による本格的な講義を、誰でも無料で受けられるウェブサービスです。

真面目な学習サイト。無料の講座も多くありそう。 期限が切られているので、義務感があります。 計画的な人に向いていそうです。

Progate

https://prog-8.com/

Progateはオンラインでプログラミングが学べるサービスです。 学び方で、結果は変わります。初心者でも学びやすい学習環境をご用意。

プログラミングに特化した教育サイト。 プログラミングの最初の難関は環境構築かと思います。 Progateは学習がウェブで完結しますので、とても手軽に学習を開始できます。 レッスンの最初の方は無料で、学習が進むと有料になります。

paizaラーニング

https://paiza.jp/works

paizaラーニングは、オンラインでプログラミングしながらスキルアップできる、プログラミング入門学習コンテンツです。

プログラミングの学習サイトです。 様々な問題にチャレンジし、ライバルと競い合えます。

問題を解いていくと、平均年収が表示されたりします。現実が突きつけられる…

f:id:s-densan:20200121215656p:plain
paizaラーニング

結果次第で企業からオファーがかかる、かも。

コードクロニクル

https://paiza.jp/codechronicle

RPG感覚でプログラミングが学べるゲーム

最近始まったサービスらしいですが、 こ、これは…

少しプレイしてみようかと思います。

そういえばディズニーのテクノロジア魔法学校というのもありましたね…

終わりに

ジャンルが多彩なgacco、特徴的なコードクロニクルに手を出してみようかとおもいます。 面白い発見があったらまた記事を書きます。

Juliaで数理計画入門

前置き

数理計画の講義を受けてきました。 学生時代に授業を受けたことがありますが、なかなか仕事で扱うことが少ないものです。

使う機会がないので忘れ去られがちですが、Excelにはソルバープラグインという数理計画問題を解くための機能が存在します。

先代から伝わる遺物「Microsoft Office 2007 Professional」の出番です。

オプションからアドインを有効化。配色が古めかしい趣がありますね。

f:id:s-densan:20191205214459p:plain

ソルバーアドインを有効にします。

f:id:s-densan:20191205214524p:plain

…………………………………………

f:id:s-densan:20191205214557p:plain

あー、だめでした。 インストールが悪かったのかもしれませんが…

ということで方針転換。自分でプログラムを作ることにします。

今をときめく言語「Python」、ではなく、新進気鋭の言語「Julia」を使ってみました。

環境設定

Juliaのインストール

公式サイトからダウンロード、インストールします。 Windowsだとインストーラが用意されています。 https://julialang.org/

線形計画法パッケージの準備

Juliaは計算や分析に優れたプログラミング言語で、その目的のライブラリが多く公開されています。 今回は線形計画法パッケージ「JuMP」のインストールをします。 コマンドラインでjuliaとタイプし、REPL(対話式インタプリタモード)に入ります。 その中で以下のコマンドを実行するとJuMPとJuMPが依存するパッケージがインストールされます。

using Pkg
Pkg.add("JuMP")

同様にSolverアルゴリズムの「Clp」パッケージもインストールします。

Pkg.add("Clp")

インストールされたか確認してみます。

Pkg.installed()
Dict{String,Union{Nothing, VersionNumber}} with 2 entries:
  "Clp"  => v"0.7.0"
  "JuMP" => v"0.20.1"

大丈夫そうです。

最適化問題の定義

線形計画モデルです。前提のストーリーを書こうと思いましたが面倒なので数式のみです。

f:id:s-densan:20191205214637p:plain

最適化プログラム作成

こんな感じにしてみました。

using JuMP
using Clp

m = Model(with_optimizer(Clp.Optimizer))

# 決定変数
@variable(m, x1)
@variable(m, x2)

# 目的関数
@objective(m, Min, -2x1 - 3x2)

# 制約条件1
@constraint(m, 1x1 + 3x2 <= 24)
# 制約条件2
@constraint(m, 4x1 + 4x2 <= 48)
# 制約条件3
@constraint(m, 2x1 + 1x2 <= 22)

# 最適化計算の開始
JuMP.optimize!(m)

println("目的関数: ", JuMP.objective_value(m))
println("x1 = ", JuMP.value(x1))
println("x2 = ", JuMP.value(x2))

出力結果

Coin0506I Presolve 3 (0) rows, 2 (0) columns and 6 (0) elements
Clp0006I 0  Obj 0 Dual inf 0.0499998 (2) w.o. free dual inf (0)
Clp0006I 0  Obj 0 Dual inf 0.0499998 (2) w.o. free dual inf (0)
Clp0006I 2  Obj -30
Clp0000I Optimal - objective value -30
Clp0032I Optimal objective -30 - 2 iterations time 0.062
目的関数: -30.0
x1 = 5.999999999999999
x2 = 6.0

多分、あってる、はずです。

まとめ

Juliaで計算をしてみましたが、優れたライブラリが公開されているので簡単、かつソルバーの入れ替えも可能で自由度が高いなという印象を受けました。 今回は単純な計算だったので実感はできませんでしたが、高速に動作するとのことです。 まだまだメジャーとは言い難いですが、プログラミング言語の選択肢の一つに加えてみてはいかがでしょうか。

GROWIのAPIを使ってwiki管理を自動化

はじめに

倶楽部の情報管理に、メルカリが作った社内wiki「Crowi」の派生である、「GROWI」を使用しています。 このCrowiおよびGROWI、通常はページの作成や閲覧はインターネットブラウザを使用して行います。 しかし、実は公式には書かれていませんが、ページの取得や作成といった操作を実行できるAPIが公開されています。

倶楽部の定例会を行う場合、イベントページを作成するのですが、以下の操作がほぼルーチンとなっています。

  1. Templateページを複写してイベントページを作成
  2. ページ名とページ内の日にち情報を、次のイベントの日付に変更
  3. 次のテーマやスピーカーを記載
  4. SlackにイベントページのURLと次のイベント日付を含むお知らせメッセージを投稿

これ等の操作を公開APIを使って自動化できないか挑戦してみました。

※GROWIとして記載しますが、多分Crowiでも同じことができます。

GROWIのAPIについて

公式の文書がないので有志の作った記事やGithubで公開されているソースコードを解析するしかありません。

例えばページ関係のAPIは以下に記載されています。 https://github.com/crowi/crowi/blob/master/lib/controllers/page.ts ページを@apiで検索すると該当する関数が見つかります。

ページを作成するpages.listに注目してみます。 リクエストメソッドはGET、引数はpathuserということがわかります。

これを用いて、ページ一覧を取得するには以下のアドレスにアクセスすればいいです。

(プロトコル)://(ホストアドレス)/_api/pages.list?access_token=(アクセストークン)&path=/

書き忘れていましたが、アクセストークンを予め取得しておく必要があります。 アクセストークンはあなたのGROWIにアクセスし、右上の「あなたの名前」「ユーザ設定」「API設定」で取得できます。 URLのaccess_tokenに設定してください。

userpathは選択のようで、今回はpath/を指定して、すべてのページを取得しました。

もう一つ、ページを作成するpages.createが見つかります。 リクエストメソッドはPOST、引数はbody,path,grantのようです。

postなのでURL直打ちで実行はできません。サクッとプログラムを書いてみましょう。 言語はPythonです。

import requests

protocol = 'https'
host_address = 'naisho.com'
access_token = 'hImItSuHiMiTsUhImItSuHiMiTsU'

def pages_create(path, body):
    url = f'{protocol}://{host_address}/_api/pages.create'
    res = requests.post(url, data={'body':body, 'path':path, 'access_token':access_token})
    print(res.json())

pages_create('/test', '# Test\n\nこのページは自動作成のテストによってい生成されたページです。')

ちゃんと作成されました。誤植までバッチリです。

f:id:s-densan:20191112214917p:plain

自動化プログラムの作成

  • /event/template/定例会テンプレートにある定例会イベントのテンプレートをコピーして、次回の定例会ページを/event作成します。
  • 新規ページのパスや内容で使用する年月日情報はユーザが入力できるようにする。

まずはAPIでTemplateページのコピーをしたいと思いましたが、コピー用のAPIは無い?ようです。なので、ページ情報取得のpages.getpages.createを組み合わせて作ります。 pages.getを調べておきます。 リクエストメソッドはGET、引数はpage_idpathrevision_idとのこと。おそらくpage_idpathは選択で、revision_idはオプションでしょう。

https://wiki.s-densan.tk/_api/pages.get?access_token=uxPFdApsClWsUvpCImD1G7pNh6j9/STajo/5NhvUyUg=&path=(ここにtemplateページのパス)

ちゃんとデータが表示されます。

プログラムで書くとこうなります。

import requests

protocol = 'https'
host_address = 'naisho.com'
access_token = 'hImItSuHiMiTsUhImItSuHiMiTsU'

def pages_get(path):
    url = f'{protocol}://{host_address}/_api/pages.get'
    res = requests.get(url, params={'path':path, 'access_token':access_token})
    return res.json()

print(pages_get('/event/templates/定例会テンプレート')['page']['revision']['body'])

さて、ここまでできれば材料が揃いました。 あと実施することは以下の通り。

  • 標準入力で、次の定例会の日時をyyyymmdd形式で入力させる
  • ページのパスを/event/yyyymmdd_mm月定例会となるよう組み立てる
  • ページ内の{yyyy}をyyyy、{mm}をmm、{dd}をddに置き換える。
  • pages.createを呼び出す
import requests

protocol = 'https'
host_address = 'naisho.com'
access_token = 'hImItSuHiMiTsUhImItSuHiMiTsU'

def pages_create(path, body):
    url = f'{protocol}://{host_address}/_api/pages.create'
    requests.post(url, data={'body':body, 'path':path, 'access_token':access_token})

def pages_get(path):
    url = f'{protocol}://{host_address}/_api/pages.get'
    res = requests.get(url, params={'path':path, 'access_token':access_token})
    return res.json()

yyyymmdd = input('Enter yyyymmdd: ')
if yyyymmdd.isdecimal() and len(yyyymmdd) == 8:
    yyyy = yyyymmdd[0:4]
    mm = yyyymmdd[4:6]
    dd = yyyymmdd[6:8]
    template_body = pages_get('/event/templates/定例会テンプレート')['page']['revision']['body']
    template_body = template_body.replace('{yyyy}', yyyy)
    template_body = template_body.replace('{mm}', mm)
    template_body = template_body.replace('{dd}', dd)
    page_path = f'/event/{yyyymmdd}_{mm}月定例会'
    
    pages_create(page_path, template_body)

まとめ

GROWIは使いやすくて気に入っていましたが、画面操作があるので定例作業は面倒だと感じていました。 APIを使うと面倒な作業はプログラムに任せ、コンテンツの作成に集中できます。 Google App Scriptの定期実行機能やSlackの連携機能など組み合わせることで、もっと面白いことができそうですね。

Japan IT Week 2019秋

はじめに

11/23~25に千葉で行われた、Japan IT Week 2019秋に行ってきました。 複数の展示会が合同で行われていたのですが、主にIoT/M2M展、AI・業務自動化展を見てきました。 よく目についた言葉について、簡単にレポートします。

よく目についた言葉

以下3つの言葉をよく聞きました。

  • RPA
  • ビジネスチャット
  • LPWA

RPAとビジネスチャットは近年耳にタコができるくらい聞きますね。 それに比べてLPWAは、私が知ったのはここ数ヶ月以内です。ネットの記事を調べても2019年のものが多いようです。

それぞれに付いてもうちょっと詳しく記載します。

RPA

みんな大好き単調作業を、肩代わりしてくれるロボットソフトウェア。 これが普及すれば単調仕事がなくなって、より生産的な仕事に注力できるようになります。人間にとってはより辛くなる気が…

前回の展示会ではUiPathやWinActorなどの大手が目立ちましたが、今回はそれに加えて簡易で安価なRPAが多数出展されていました。 導入がしやすくなってきましたが、乱立して選定が難しくなってきている印象を受けます。

ビジネスチャット

セミナーでChatworkとMicrosoft Teamsの紹介がされていました。 Slackを加えて(私が思う)日本でメジャーなビジネスチャット3選です。 チャットは、手紙・電話・メールに続いて、次のコミュニケーションツールとして期待されています。

実際に導入するには社内教育のコスト、クラウドシステム禁止制度、費用対効果の算出が難しいなどハードルは多いですが、いつかはメールに取って代わりそうな勢いです。

LPWA

低消費電力・広域な無線の総称です。 規格によっては数十km飛び、乾電池電池で数年も駆動するということで、IoTのセンサーデータの送信で活躍を期待されています。 ただ、通信帯域は広くないので、エッジで処理した結果のみ送信するなどの工夫が必要そうです。

LPWAの1つ「LoRa」のワイドエリア対応規格の「LoRaWAN」は、とやまものづくりプラットフォームでも使われています。

まとめ

業務効率化はRPAもチャットも知名度が上がったり多様なサービスが生まれたりして、導入しやすい環境が整ってきました。 IoTはまだまだ周辺技術が発展しそうです。

今後は今回調べた各項目についてもう少し掘り下げた調査をしていきたいですね。

画像処理の復習

引き続き、大学でIoTのリカレント教育に出ています。

講義では「生産現場の技術者向け」を対象としているので、コンピュータの技術面についてあまり深いところに突っ込みません。

先日の画像処理の演習でも、プログラミングすると言うよりは与えられたコードをただ実行して体験するものでした。

身につけるためにも自宅で実際に調べながら作ってみました。 講義ではRaspberry Piを使っていましたが、Raspberry Pi用のカメラを繋ぐのが面倒なので、実行環境はWindows PCで、カメラは市販のWebカメラを使用しました。 言語はPython、画像処理ライブラリはOpenCV2を使っています。

背景差分

背景との差分を取り、動きのあった場所を検出します。 createBackgroundSubtractorMOG2で生成されるオブジェクトを使うだけで、考えて作るとことは殆どありません。その他の有名なアルゴリズムも呼び出すだけで使えるようです。

from cv2 import cv2

cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()

while True:
    ret, frame = cap.read()
    cv2.imshow('', fgbg.apply(frame))
    k = cv2.waitKey(1)
    if k==27:
        break
cap.release()
cv2.destroyAllWindows()

こんな感じ。ものを動かすと白くなり、差分が検知されているのがわかります。

f:id:s-densan:20191016000206g:plain

円・直線検出

円や直線のような画像に赤色でマーキングします。 こちらも検出自体はHoughCirclesHoughLinesが全部やってくれます。

from cv2 import cv2
import math
import numpy as np

cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()


def mask_circle(img):
    height, width = img.shape[:2]
    mask_color = (0,0,255)
    
    # グレイスケールに変換
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 円検出
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=1,
                               minDist=50, param1=120, param2=40, minRadius=40, maxRadius=100)
    # 255で埋まった3次元配列(縦x横xRGB3次元)を生成
    mask = np.full((height, width, 3), 255, np.uint8)
    if circles is not None:
        for cs in circles:
            for c in cs:
                mask = cv2.bitwise_or(mask, cv2.circle(mask, (c[0], c[1]), 80, mask_color, 20))
    return mask

def mask_line(img):
    height, width = img.shape[:2]
    mask_color = (0, 0, 255)
    
    # グレイスケールに変換
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.Canny(gray, 50, 150, apertureSize=3)
    # 円検出
    lines = cv2.HoughLines(gray, 1, np.pi/180, 200)
    # 255で埋まった3次元配列(縦x横xRGB3次元)を生成
    mask = np.full((height, width, 3), 255, np.uint8)
    if lines is not None:
        for rho, theta in lines[0]:
            
            x1 = int(np.cos(theta)*rho - 1000*np.sin(theta))
            y1 = int(np.sin(theta)*rho + 1000*np.cos(theta))
            x2 = int(np.cos(theta)*rho + 1000*np.sin(theta))
            y2 = int(np.sin(theta)*rho - 1000*np.cos(theta))

            mask = cv2.bitwise_or(mask, cv2.line(mask, (x1, y1), (x2, y2), mask_color, 2))
    return mask

mask_types = [('circle', mask_circle),
              ('line', mask_line)]

selection = 0

while True:
    width = 640
    height = 480
    ret, frame = cap.read()
    img = cv2.resize(frame, (width, height))
    
    if mask_types[selection][1] is not None:
        mask = mask_types[selection][1](frame)
        masked_img = cv2.bitwise_and(img, mask)

        img_with_text = cv2.putText(masked_img, mask_types[selection][0], (0, 30), 0, 1, (255, 255, 255))
        cv2.imshow('masked', img_with_text)
    k = cv2.waitKey(1)
    if k == 27:
        break
    elif k == ord('z'):
        selection = (selection - 1) % len(mask_types)

cap.release()
cv2.destroyAllWindows()

こんな感じ。円と線が検知されています。

f:id:s-densan:20191015235940g:plain

f:id:s-densan:20191016000333g:plain

まとめ

OpenCV2はプリセットが充実していて、サクッと作るだけなら簡単にできます。いかに精度を上げるか、分析結果をどう表現するか、今後も勉強していきます。