ホーム ブログ ページ 64

カスタマーへの活用促進とヘルススコア

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ザ・モデルという本にカスタマーサクセスの少し取り上げられていたので一部のまとめる

カスタマーサクセスとは

カスタマーサクセスとはお客様との契約から運用サポートまでの一連のプロセスの総称。
営業担当や導入担当、カスタマーサポート担当などの様々なやりとりに関わる。
特にカスタマーサクセス担当者は、導入直後の活用促進やヘルススコアのUPに注力し、
契約更新の安定化とアップセル/クロスセルを行う。

活用促進

サービス活用のロードマップを定義し、
社内状況やサービス規模から次に行う施作の提案を行うこと。

活用ロードマップ例

  • レベル1 キャンペーンを行い、データをレポート化すること。
  • レベル2 過去のレポートの結果から次に行うキャンペーンや施作の意思決定を行うこと。
  • レベル3 複数の部門や組織と連携し、複数年度に渡る目標達成の計画に使用すること。
  • レベル4 グローバル展開に使用すること。

ヘルススコア

お客様のサービス活用度や社内状況から、更新リスクの可能性を数値化すること。

ヘルススコアの要素の例

  • 契約金額
  • 年少
  • 成長企業
  • 活用拡大余地
  • 活用度
  • 問い合わせ回数
  • 担当者数
  • 導入時の目的の達成度
  • 事例紹介可否
  • セミナー参加回数 etc..

参考文献
THE MODEL(MarkeZine BOOKS) マーケティング・インサイドセールス・営業・カスタマーサクセスの共業プロセス  (著) 福田 康隆

アクセス解析の重要性 時代はAIDMAからAISCEASへ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

はじめまして。

アクセス解析チーム、コンサルタント見習いの大山です。

ユーザビリティ・アクセシビリティに強いコンサルタントを目指しています。

どうぞよろしくお願いします。

■「【アクセス解析×ユーザビリティ】おこしやす!アクセス解析」ってどんなブログ?

本ブログでは、「アクセス解析」の話題を

「ユーザビリティ・アクセシビリティを高める」というテーマに視点を置き、

解析結果から問題点を洗い出し、とるべき施策・その効果までを書かせていただきます。

具体的には、

・そもそもアクセス解析とは?

・分析したけど、データの活かし方がわからない・・・

・Webサイトに対するユーザの行動心理って?

・ゴールまで到達しないのはなぜ?

・サイトの回遊を促したい・・・

などなど

自身の勉強も兼ねて、少しでも解析のお役に立てるものを掲載していきたいと思います。

まだまだ見習いですので、至らない部分は多々あると思いますが、

温かい目で見守っていただければ幸いです。。。

■そもそもアクセス解析はどうして必要なの?

Webサイトを運営するに当たって欠かせないアクセス解析。

いざ、アクセス解析ツールを導入したははいいものの、

ツールはデータの収集にすぎないので、次にとるべきアクションを教えてはくれません。

使い方によっては無意味なものになることだってあります。

そもそもアクセス解析はなぜ、近年において重要視されているのでしょうか?

アクセス解析が重要視される背景として、

消費者行動の移り変わりが理由の一つとして挙げられます。

・AIDMAの法則からAISCEASの法則へ

「AIDMA(アイドマ)の法則」をご存知ですか?

学校の授業やテレビ等で一度は耳にしたことがあるかと思います。

AIDMAとは・・・

1920年代にアメリカ合衆国の販売・広告の実務書の著作者であった

サミュエル・ローランド・ホールが著作中で示した広告宣伝に対する

消費者の心理のプロセスを示した略語です。

AIDMAの法則では、消費者がある商品を知って購入に至るまでに

次のような段階があるとされる。

  1. Attention (注意)
  2. Interest (関心)
  3. Desire (欲求)
  4. Memory (記憶)
  5. Action (行動)

(Wikipediaより)

ほとんどの消費者プロセスはAIDMAによって説明付くものだと思います。

しかし、近年ではインターネットを通して物を購入することが多くなり、

消費者の行動場所が現実からパソコンの中へと移り変わりつつあります。

商品の価格比較や口コミなど、実店舗ではなかなか得られない情報を

ボタン一つで簡単に得られることが、理由の一つとして挙げられます。

そんな新しい消費者行動モデルとして、

近年、「AISCEAS(アイシーズ)の法則」((有)アンヴィコミニケーションズの商標)が提唱されています。

AISCEASとは次のような消費者行動を指します。

  1. Attention (注意)
  2. Interest (関心)
  3. Search (検索)
  4. Compare (比較)
  5. Examination (検討)
  6. Action (行動)
  7. Share (共有)

行動は細分化され、ユーザがインターネットを使い慣れてきたことが伺えます。

・AISCEASの法則からわかること

近年の細分化された消費者行動によりわかること、

それはユーザの行動履歴がインターネット上に増え続けていることです。

つまり、自身のWebサイトへ訪れたユーザの行動履歴を知ることで

より戦略的なサイト作りに欠かせない情報を得られるのです。

・自身のサイトへどのようなキーワードでSearch (検索)したのか

・Compare (比較)やExamination (検討)の対象となるページ毎の

 閲覧時間やPV数、ゴールページまでにたどり着く確立、等

・ユーザが自身のサイト内でとるAction (行動)

を、アクセス解析では見ることができます。

アクセス解析結果には、Webサイトに対するニーズやユーザの動向を知るヒントが多く存在します。

Webサイトの最適化、最大化は多くのWeb担当者の目標ではないでしょうか。

近年、激化するインターネット時代において、

Webサイトの目標を達成のための施策を打つには、

アクセス解析はなくてはならないものであると考えられます。

今回は、 アクセス解析が必要な理由を簡単に書かせいていただきましたが、

次回以降、データの収集後に次にとるべきアクションの具体策などを掲載していこうと思います。

しかし、予定は未定ですのであしからず・・・

では、また。

postgresでorder byに複数のカラムを使うとdesc句を使った場合、indexを使用しない件

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Postgresqlに限らず、インデックスを利用する/利用しないは、

DBを使ったシステムの速度を決める重要な要件だったりします。

今回は、業務中に突き当たった複数のカラムを指定していた場合

DESCやASCを使っていた場合、indexを利用しなかったpostgresの

対応方法について説明します。

なお、突き当たったバージョンは8.1.9でした。

対象はたいした事は無いsql文なのですが、こういったsql文です。

SELECT

entries.id,entries.title, entries.body, entries.entry_type, entries.created_at, entries.updated_at

FROM

entries

ORDER BY

entry_type,updated_at DESC

indexは、 entry_type, updated_atの複合indexを張っています。

ですがコレがindexを利用しない。

DESC句を外すと利用するんですけどね。

というわけで幾つか検索した所、以下の2つの情報を参照して解決しました。

http://itpro.nikkeibp.co.jp/article/COLUMN/20051117/224817/?P=5

http://d.hatena.ne.jp/poch-7003/20070913/1189691482

今回はtimestamp型ですので、postgresから

rails_db=# ¥df *cmp

とした結果の

Schema | Name | Result data type | Argument data types

————+———————-+——————+———————————————————-

pg_catalog | bitcmp | integer | bit, bit

pg_catalog | bpcharcmp | integer | character, character

pg_catalog | btabstimecmp | integer | abstime, abstime

pg_catalog | btarraycmp | integer | anyarray, anyarray

pg_catalog | btboolcmp | integer | boolean, boolean

pg_catalog | btbpchar_pattern_cmp | integer | character, character

pg_catalog | btcharcmp | integer | “char”, “char”

pg_catalog | btfloat48cmp | integer | real, double precision

pg_catalog | btfloat4cmp | integer | real, real

pg_catalog | btfloat84cmp | integer | double precision, real

pg_catalog | btfloat8cmp | integer | double precision, double precision

pg_catalog | btint24cmp | integer | smallint, integer

pg_catalog | btint28cmp | integer | smallint, bigint

pg_catalog | btint2cmp | integer | smallint, smallint

pg_catalog | btint42cmp | integer | integer, smallint

pg_catalog | btint48cmp | integer | integer, bigint

pg_catalog | btint4cmp | integer | integer, integer

pg_catalog | btint82cmp | integer | bigint, smallint

pg_catalog | btint84cmp | integer | bigint, integer

pg_catalog | btint8cmp | integer | bigint, bigint

pg_catalog | btname_pattern_cmp | integer | name, name

pg_catalog | btnamecmp | integer | name, name

pg_catalog | btoidcmp | integer | oid, oid

pg_catalog | btoidvectorcmp | integer | oidvector, oidvector

pg_catalog | btreltimecmp | integer | reltime, reltime

pg_catalog | bttext_pattern_cmp | integer | text, text

pg_catalog | bttextcmp | integer | text, text

pg_catalog | bttintervalcmp | integer | tinterval, tinterval

pg_catalog | byteacmp | integer | bytea, bytea

pg_catalog | cash_cmp | integer | money, money

pg_catalog | date_cmp | integer | date, date

pg_catalog | interval_cmp | integer | interval, interval

pg_catalog | macaddr_cmp | integer | macaddr, macaddr

pg_catalog | network_cmp | integer | inet, inet

pg_catalog | numeric_cmp | integer | numeric, numeric

pg_catalog | time_cmp | integer | time without time zone, time without time zone

pg_catalog | timestamp_cmp | integer | timestamp without time zone, timestamp without time zone

pg_catalog | timestamptz_cmp | integer | timestamp with time zone, timestamp with time zone

pg_catalog | timetz_cmp | integer | time with time zone, time with time zone

pg_catalog | varbitcmp | integer | bit varying, bit varying

(40 rows)

Argument data typesに、型が書いてあるので、使いたい型を選びます。

今回は、updated_atなので、timestamp型となり、timestamp_cmpを利用しました。

で、その逆の関数を作成します。

CREATE OR REPLACE FUNCTION timestamp_cmp_rev(TIMESTAMP, TIMESTAMP) RETURNS INTEGER AS $$ SELECT timestamp_cmp($2,$1);$$ LANGUAGE sql

その後、参考URLに書いてある通り作成しました。

CREATE OPERATOR CLASS timestamp_desc_ops FOR TYPE TIMESTAMP USING BTREE AS OPERATOR 1 >, OPERATOR 2 >=, OPERATOR 3 =, OPERATOR 4 <=, OPERATOR 5 <,FUNCTION 1 timestamp_cmp(timestamp, timestamp)

で、indexを作成しました。

CREATE INDEX index_entries_on_entry_type_and_updated_at ON

entries(entry_type, updated_at timestamp_desc_ops)

これで検索するとインデックスを使用してくれました。

もし「もっと良いやり方あるよ」と言う方いらっしゃいましたら是非教えて下さい。

なお、8.3からdescで指定できるようです...苦労はなんだったんだろう。

Google Analyticsとは?

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

はじめまして。

KBMJいちのビギナー、アクセス解析チーム-アシスタント、ミラノです。
どうぞよろしくお願いいたします。


本日は、皆さんすでにご存じかとは思いますが、Google Analyticsについて簡単に説明させていただきます。■Google Analyticsとは?

Googleが提供する高性能な無料アクセス解析ツールです。
Googleアカウントを取得し、Webサイトの各ページに「トラッキングコード」と呼ばれるJavaScriptのコードを挿入すれば、誰でも使用が可能です。
Urchinという企業向けの高機能なアクセス解析ツールをベースとしており、
Urchinのほぼすべての機能が無料で利用できる画期的なアクセス解析ツールです。

■Google Analyticsの特徴

・グラフを多用した見やすい画面
・豊富なデータ量
・操作が(慣れれば)簡単
・充実した分析機能(ページ遷移の分析・コンバージョン測定)
・広告の効果測定
・エクスポートが簡単

*Google Analytics サンプルイメージ
Google Analyticsの見やすいグラフ

*Google Analyticsのページはこちら
 http://www.google.com/analytics/ja-JP/

■Google Analyticsでわかること

・アクセスが集中するのは何曜日の何時頃なのか?
・訪問者は一見さんなのか、常連さんなのか?
・ユーザーがたどったサイト内経路は?
・ユーザーが最後に見たページはどれか?
・人気のあるページは?
・どんな検索キーワードでページにたどり着いたのか?

Google Analyticsで上記を把握し、より良いサイト環境作りのヒントを得ることが出来ます。

最終的には、
Increase conversions, and make more money on the web!(Google Analytics Helpより)
Google Analytics使って目標を達成して、WEBでもっと儲けよう!

今後はGoogle Analyticsの設定・活用方法などを掲載していきたいと思います。

高性能で無料でCOOLなGoogle Analyticsを一緒にCheck it outしていきましょう;)

IE6でposition:absoluteしたボックスが消えるバグ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。maiです。
IE7の登場により徐々にシェアを減らしつつあるIE6ですが、
そうはいってもまだまだ健在です。
そしてそのバグもまだまだ健在です…。

今回はpositionの値をabsoluteにしたボックスが、
なぜかIE6で見えなくなってしまうバグについてその対処法をご紹介です。

このバグ「absolute position disappearing bug」というバグらしいのですが、
代表的なものに比べると、あまり知られていないことからわかるように、
ものすごく限定状況で起きるバグです。

今回私が遭遇したのはこのケース

1:position:absoluteしたdiv
2:float:leftしたdiv
3:float:rightしたdiv

positionの値がabsoluteで、なおかつすぐ次に続く要素がfloatしていること
が私の場合の発生原因だったようです。
この場合の回避方法は…

1:position:absoluteしたdiv
2:空っぽのdiv
3:float:leftしたdiv
4:float:rightしたdiv

これです。 スマートじゃないですね。わかってます。
でもどうやらこのバグを回避するにはスマートじゃないやり方しかないようです。
一番スマートなのは、このバグが発生しないようにデザインを組むこと…ですね。

なお、上記を含めたこのバグの発生条件と回避方法については
以下のページがわかりやすくまとまってます。
Win/IEで絶対配置(position: absolute)のボックスが消えるバグの検証ページjmblog.jp

ActionScript 3 でマウスを追いかけるアニメーションを作成する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回は ActionScript 3 を使って、マウスを追いかけるアニメーションを作成してみます。

Arrow.as

package{
    import flash.display.*;

    // 矢印クラス
    public class Arrow extends Sprite {
        public function Arrow(){
            init();
        }

        // 矢印を描画する
        public function init():void{
            // 枠のスタイルを設定
            graphics.lineStyle(2,0,1);
            // 塗りつぶしの色を設定
            graphics.beginFill(0xff0000);

            graphics.moveTo(-50,-25);
            graphics.lineTo(0,-25);
            graphics.lineTo(0,-50);
            graphics.lineTo(50,0);
            graphics.lineTo(0,50);
            graphics.lineTo(0,25);
            graphics.lineTo(-50,25);
            graphics.lineTo(-50,-25);
            graphics.endFill();
        }
    }
}

ChaseCursor.as

package{
    import flash.events.*;
    import flash.display.*;

    public class ChaseCursor extends Sprite {
        // スピード
        private var s:Number = 10;
        // 矢印オブジェクト
        private var a:Arrow;

        public function ChaseCursor(){
            init();
        }

        private function init():void{
            // フレーム更新イベントを設定
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
            // 矢印オブジェクトを生成
            a = new Arrow();
            // 矢印オブジェクトと画面に追加
            addChild(a);
        }

        // フレームイベント
        private function onEnterFrame(e:Event):void{
            // 矢印の座標とマウスカーソルの座標との差分を算出
            var dx:Number = mouseX - a.x, dy:Number = mouseY - a.y;
            // 矢印の座標とマウスカーソルの座標との角度を算出
            var d:Number = Math.atan2(dy, dx);
            // 矢印オブジェクトの速度を算出
            var vx:Number = Math.cos(d) * s, vy:Number = Math.sin(d) * s;
            // 速度に基づいて矢印の位置を更新
            a.x += vx, a.y += vy;
            // 矢印オブジェクトの角度を設定
            a.rotation = d / Math.PI * 180.0;
        }
    }
}

ChaseCursor-app.xml

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://ns.adobe.com/air/application/1.5">
  <id>ChaseCursor</id>
  <version>0.1</version>
  <filename>ChaseCursor</filename>
  <initialwindow>
    <content>ChaseCursor.swf</content>
    <visible>true</visible>
    <systemchrome>standard</systemchrome>
    <transparent>false</transparent>
  </initialwindow>
</application>

コンパイルする

% amxmlc ChaseCursor.as

実行する

% adl ChaseCursor-app.xml

実行結果

赤い矢印がマウスカーソルを追いかけます。

http://farm4.static.flickr.com/3088/3200192579_6c1c90cd0d.jpg

さいごに

ActionScript 3 でアニメーションを作成する時は、位置と速度を変数に保持すると管理しやすくなります。

皆さんも是非お試し下さい。

個人ブログ 拡張現実ライフ

RMagick を使って輝きのあるバナー画像を作成する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回は RMagick を使って、Web2.0 っぽいバナー画像を作成してみます。

ImageMagick とは

ImageMagick とは、画像ファイルを加工するための機能を提供してくれるプログラムです。

RMagick とは

RMagick とは、ImageMagick を ruby で扱えるようにしたものです。

ImageMagick のインストール(MacOSX で MacPorts を使ってインストールする場合)

% sudo port install ImageMagick

RMagick のインストール

% sudo gem install rmagick

コードを書く

require 'RMagick'
include Magick

WIDTH = 650
HEIGHT = 40

# 画像リストを作成
stripes = ImageList.new

# グラデーションを作成
top_grad = GradientFill.new(0, 0, WIDTH, 0, "#dddddd", "#888888")
# グラデーション画像を作成
image1 = Image.new(WIDTH, HEIGHT, top_grad)
# グラデーション画像を保存
image1.write('image1.png')
# グラデーション画像をリストに追加
stripes << image1


# グラデーションを作成
bottom_grad = GradientFill.new(0, 0, WIDTH, 0, "#757575", "#555555")
# グラデーション画像を作成
image2 = Image.new(WIDTH, HEIGHT, bottom_grad)
# グラデーション画像を保存
image2.write('image2.png')
# グラデーション画像をリストに追加
stripes << image2

# 画像を上下方向に連結
combined_grad = stripes.append(true)
# 連結した画像を保存
combined_grad.write('image3.png')

# 連結した画像を複製
image4 = combined_grad.clone
# 文字列を描画
gc = Draw.new
gc.font = '/Library/Fonts/ヒラギノ明朝 Pro W3.otf'
gc.fill = 'white'
gc.stroke = 'none'
gc.pointsize = 60
gc.annotate(image4, 0, 0, 10, 60, "Do Ruby!")
# 文字列を描画した画像を保存
image4.write('image4.png')

処理を実行する

% ruby web20.rb

実行結果 image1.png の内容

http://farm4.static.flickr.com/3297/3197802303_3f7d0f1bca.jpg

実行結果 image2.png の内容

http://farm4.static.flickr.com/3264/3197802345_c3a5d4e67c.jpg

実行結果 image3.png の内容

http://farm4.static.flickr.com/3406/3198648982_cd7b2975a6.jpg

実行結果 image4.png の内容

http://farm4.static.flickr.com/3268/3197802383_fbae00a2a9.jpg

さいごに

RMagick を使うと、Photoshop で作成したような画像も Ruby スクリプトを記述することによって生成することができます。

皆さんも是非お試し下さい。

個人ブログ 拡張現実ライフ

RMagick を使って写真の特定色域を別の色で塗りつぶす

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回は RMagick を使って、写真の特定色域を別の色で塗りつぶしてみます。

ImageMagick とは

ImageMagick とは、画像ファイルを加工するための機能を提供してくれるプログラムです。

RMagick とは

RMagick とは、ImageMagick を ruby で扱えるようにしたものです。

ImageMagick のインストール

% sudo port install ImageMagick

RMagick のインストール

% sudo gem install rmagick

コードを書く

require "rubygems"
require "RMagick"

include Magick

img = ImageList.new("kbmj-src.jpg")

compare = Magick::Pixel.new(142*256,72*256,2*256) # この色と近い領域を探す
replace = Magick::Pixel.new(255*256,0,0) # この色で塗りつぶす
for y in 0...img.rows
  for x in 0...img.columns
    src = img.pixel_color(x, y) # 元画像のピクセルを取得

    dr = src.red - compare.red # 赤要素の差
    dg = src.green - compare.green # 緑要素の差
    db = src.blue - compare.blue # 青要素の差

    # RGB空間上において2つの色が近ければ置換する
    img.pixel_color(x, y, replace) if dr*dr + dg*dg + db*db < (30*256*30*256)*3
  end
end

img.write("kbmj-out.jpg")

処理対象の画像を用意する

今回は弊社のパンフレットをiPhoneのカメラで撮影したものを用意しました。

http://farm4.static.flickr.com/3416/3195992288_466c34ab2e.jpg

処理を実行する

% ruby rmagick.rb

実行結果

オレンジの領域が赤で塗りつぶされています。

http://farm4.static.flickr.com/3106/3195176725_8ab26f966f.jpg

さいごに

RMagick を使うと Ruby で画像処理ロジックを記述できますので、irb で各種実験を行うなど、手軽に画像処理を行うことが可能です。

皆さんも是非お試し下さい。

個人ブログ 拡張現実ライフ

case文の落とし穴

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

初めまして、エンジニア一年目のサンドリバー砂川です。

今回は開発中につまずいたcase文の挙動について解説をします。

こんな感じのcase文を考えてみます。

class Obj
  class Foo
  end

  class Bar
  end
end

obj = Obj::Foo

case obj
  when Obj::Foo
    puts "obj is Foo."
  when Obj::Bar
    puts "obj is Bar"
  else
    puts "obj is unknown...."
end

スクリプトを実行してみると

obj is unknown....

何故か比較がうまいこと出来てません。

実はcase文ではこんな風に比較が行われます。

case obj
  when Obj::Foo
end
↓
if Obj::Foo === obj

問題は演算子===で、こいつは呼び出したオブジェクトの型によって挙動が変わります。

例えばString#===なら==と同じ挙動ですが、Class#===の場合はkind_of?と同じ挙動になります。

kind_of?メソッドは、引数が呼び出したオブジェクトのインスタンスの場合にtrueを返します。

今回のコードではobj = Obj::Fooとクラスオブジェクト自体を代入していたのでfalseになってしまったんですね。

なので解決策として、objにインスタンスを代入する。

obj = Obj::Foo.new

あるいはto_sメソッドを利用して比較する。

case obj.to_s
  when Obj::Foo.to_s
    puts "obj is Foo."
  when Obj::Bar.to_s
    puts "obj is Bar"
  else
    puts "obj is unknown...."
end

obj is Foo.

で解決です。

Rails と MeCab で Twitter の発言内容を解析する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回は Rails と MeCab を使って Twitter の発言内容を解析してみます。

MeCab について

MeCab はオープンソースの形態素解析エンジンです。

Mechanize のインストール

% sudo gem install mechanize

Hpricot のインストール

% sudo gem install hpricot

Mecab のインストール

% sudo port install mecab
% sudo port install mecab-ipadic-utf8
% sudo port install rb-mecab

マイグレーションファイルを書く

class CreateStatuses < ActiveRecord::Migration
  def self.up
    create_table :statuses do |t|
      t.column :text, :string
      t.column :screen_name, :string
      t.timestamps
    end
  end

  def self.down
    drop_table :statuses
  end
end

コードを書く

require "rexml/document"
require "open-uri"
require 'MeCab'

module MeCab
  class Node
    def category
      return self.feature.split(/,/)[0]
    end

    def each(&b)
      b[self]
      self.next.each(&b) if self.next
    end
  end
end

class Status < ActiveRecord::Base
  def self.get_xml_page(user, page)
    xml = open("http://twitter.com/statuses/user_timeline/#{user}.xml?page=#{page}").read # XMLを取ってくる
    doc = REXML::Document.new xml
    doc.elements.each('/statuses/status') do |s|
      text = s.elements["text"].text # 発言内容を取得
      screen_name = s.elements['user/screen_name'].text
      p "#{screen_name} #{text}"
      status = Status.new(:text => text, :screen_name => screen_name)
      if status.save # DBに挿入
        p "SUCCESS"
      else
        p "FAILED"
      end
    end
  end

  def self.parse
    m = MeCab::Tagger.new
    h={}
    Status.find(:all).each do |s|
      nodes = m.parseToNode(s.text)
      nodes.each do |node|
        next unless node.category == '名詞' # 名詞のみ解析対象とする
        if h[node.surface]
          h[node.surface] += 1 # 出現回数をカウント
        else
          h[node.surface] = 1
        end
      end
    end
    # 結果出力
    h.to_a.sort{ |a,b|
      (b[1] <=> a[1]) * 2 + (a[0] <=> b[0])
    }.each{ |e| puts "#{e[0]} #{e[1]}"}
  end

  def self.get_xml
    Status.delete_all
    1.upto(10) do |page|
      get_xml_page('akio0911', page)
    end
    parse
  end
end

処理を実行する

ruby script/runner 'Status.get_xml'

実行結果

Twitterにおいて最近よく使っているキーワードを見ることができます。

インストール 12
:// 11
http 11
com 10
ー 10
こと 9
1 7
emacs 7
メガネ 7
人 7
会 7
会社 7
勉強 7
忘年会 7
時 7
5 6
Twitter 6
tinyurl 6
さ 6
よう 6
電源 6
0911 5
2 5
akio 5
インターネット 5
ブログ 5

さいごに

Rails と MeCab を組み合わせると、ネットから取得してきた各種情報を DB に格納したり、それに対して解析を行ったりすることが手軽にできます。

次回以降、Rails と MeCab を連携することによる応用例を書いていきたいと思います。

お楽しみに!

個人ブログ 拡張現実ライフ

Mechanize, Hpricot, MeCab でブログの頻出単語を調べる

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回は Mechanize, Hpricot, MeCab でブログの頻出単語を調べてみます。

http://farm4.static.flickr.com/3212/3101925914_6580eb0fc8.jpg

Mechanize について

Mechanize を使うと、ウェブサイトへのアクセスを自動化(リンクをたどる、フォームを submit する、リダイレクトをたどる、など)することができます。

Hpricot について

Hpricot は Ruby 用の HTML パーサです。HTML の解析や書き換えに威力を発揮するライブラリです。

MeCab について

MeCab はオープンソースの形態素解析エンジンです。

Mechanize のインストール

% sudo gem install mechanize

Hpricot のインストール

% sudo gem install hpricot

Mecab のインストール

% sudo port install mecab
% sudo port install mecab-ipadic-utf8
% sudo port install rb-mecab

コードを書く

require 'MeCab'
require 'rss'
require 'mechanize'
require 'kconv'
require 'hpricot'
require 'open-uri'

module MeCab
  class Node
    def category
      return self.feature.split(/,/)[0]
    end

    def each(&b)
      b[self]
      self.next.each(&b) if self.next
    end
  end
end

agent = WWW::Mechanize.new
page = agent.get('http://d.hatena.ne.jp/akio0911/archive') # ページを開く
m = MeCab::Tagger.new
h={}

# エントリへのリンクを抽出
page.links_with(:href => /\/\d{8}\/p\d/).each{ |l| 
  puts l.href
  doc = Hpricot(open(l.href))
  text = doc.search("div.section").text.toutf8.gsub(/\t/, "").gsub(/\n/,"") # 文章部分を取得

  nodes = m.parseToNode(text)
  nodes.each do |node|
    next unless node.category == '名詞' # 名詞以外はカウント対象としない
    next if node.surface =~ /^\d+$/ # 数字も対象としない
    if h[node.surface]
      h[node.surface] += 1
    else
      h[node.surface] = 1
    end
  end
}

# カウント結果を出力
h.to_a.sort{ |a,b|
  (b[1] <=> a[1]) * 2 + (a[0] <=> b[0])
}.each{ |e| puts "#{e[0]} #{e[1]}"}

さいごに

Mechanize, Hpricot, MeCab を使うと、ページ内容を解析するプログラムを簡単に書くことが出来ます。みなさんも是非試してみてはいかがでしょうか。

個人ブログ 拡張現実ライフ

CappuccinoとObjective-JでHello Worldを書いてみる

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回はCappuccinoとObjective-JでHello Worldを書いてみます

Cappuccino と Objective-J を使うと iPhone や Mac 向けのアプリ開発と同じ感覚で Web アプリケーションを開発することができます。

http://farm4.static.flickr.com/3151/3064248883_ffdfecd321.jpg

CappuccinoとObjective-Jについて

Cappuccino は、デスクトップソフトウェアのユーザーがうちとけやすい見た目のアプリケーションを開発するためのオープンソースフレームワークです。

Cappuccino は JavaScript などの標準的なWeb技術の上に構築されています。そしてアップルのCocoaフレームワークに非常に近い実装がなされています。

Cappuccino でプログラムしたとき、HTML, CSS, DOM などの伝統的なWeb技術を意識する必要がありません。

複雑なクロスブラウザアプリケーションを構築する際の不愉快さはありません。

Cappuccino は Objective-C をモデルとした新しいプログラミング言語である Objective-J で実装されています。Objective-J は JavaScript の上に構築されています。Objective-J で書かれたプログラムはクライアント上で翻訳されるので、プラグインなどは必要ありません。Objective-J のライセンスは LGPL となっています。

ソースコード

Hello World のソースコードを以下に示します。

import <foundation /cpobject.j>

// アプリケーションコントローラークラスである AppController を宣言します
@implementation AppController : CPObject
{
  // ラベルオブジェクトをメンバ変数として持たせます
  CPTextField label;
}

// アプリケーションの起動時に呼ばれる関数です。ここに各種初期化処理などを記述します
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
    // ウィンドウオブジェクトを生成し、そのビューを管理する contentView を取り出します
    var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
        contentView = [theWindow contentView];

    // ラベルオブジェクトを生成します
    label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
    // ボタンオブジェクトを生成します
    var button = [[CPButton alloc] initWithFrame: CGRectMake(
			     CGRectGetWidth([contentView bounds]) / 2.0 - 40,
			     CGRectGetMaxY([label frame]) + 100,
		    80, 18
		 )];
    // ボタンオブジェクトの自動リサイズに関する設定を行います
    [button setAutoresizingMask:CPViewMinXMargin |
	                        CPViewMaxXMargin |
	                        CPViewMinYMargin |
                        	CPViewMaxYMargin];

    // ボタンのタイトルを設定します
    [button setTitle:"swap"];

    // ボタンが押された際に呼ばれる処理を登録します
    [button setTarget:self];
    [button setAction:@selector(swap:)];

    // ビューにボタンを追加します。
    [contentView addSubview:button];

    // ラベルのキャプションとフォントを設定します
    [label setStringValue:@"Hello World!"];
    [label setFont:[CPFont boldSystemFontOfSize:24.0]];
    
    [label sizeToFit];
    
    // ラベルの自動リサイズ設定を行います
    [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
    // ラベルの位置を設定します
    [label setFrameOrigin:CGPointMake[1]CGRectGetWidth([contentView bounds]) - CGRectGetWidth([label frame] / 2.0, (CGRectGetHeight([contentView bounds]) - CGRectGetHeight([label frame])) / 2.0)];
    
    // ビューにラベルを追加します
    [contentView addSubview:label];
    
    [theWindow orderFront:self];

    // ラベルのキャプションを中央に設定します
    [label setAlignment:CPCenterTextAlignment];
    
    // メニューバーを表示します
    [CPMenu setMenuBarVisible:YES];
}

// ボタンが押された際に呼ばれる処理
-(void)swap:(id)sender
{
  // ラベルのキャプションを変更します
  if([label stringValue] == "Hello World!")
    [label setStringValue:"Goodbye!"];
  else
    [label setStringValue:"Hello World!"];
}

@end

さいごに

Cappuccino を使うと Mac や iPhone のソフト開発と同じ感覚で Web アプリケーションを開発することが可能です。

次回以降、Objective-J, Objective-C, Cocoa, Cocoa Touch などに関する記事を掲載していきたいと思います。

お楽しみに!

個人ブログ 拡張現実ライフ

References

References
1 CGRectGetWidth([contentView bounds]) - CGRectGetWidth([label frame]

[Rails]特定ビューだけで特定のヘルパーの関数を使いたい

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

 こんにちは。

 KBMJでRuby on Rails を使ったweb開発に携わっているyoppiといいます。

 基本的にビューで使いたい関数を持っているヘルパーはコントローラー側で読み込んであげる必要があります。ただ、あるヘルパーの関数をあるビューで使いたいというニッチな要求に対しては不便な場合があります。今回は、そのニッチな要求を簡単に満たしちゃう方法を紹介したいと思います。

 方法はとても簡単で、呼び出したい関数を持っているヘルパー(今回はHogeHelper)を読み込むコードをビューに埋め込んであげればいいだけです。

 実際は以下のようになります。

<% self.class.send(:include, HogeHelper) -%>

 こうすれば、これを記述した以降の部分で読み込んだヘルパーの関数が呼び出せるようになります。

 簡単ですね。 ヘルパー内の関数は多くなりすぎですが、このテクニックを使えば、スッキリとできるかもしれません。どこまでニーズがあるかはわかりませんが、参考にしていただくと幸いです。

Let’s  find your niche!

button_to ボタンでリンク rails

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちはカツオです。

今日は、初心に戻ってハイパーリンクではなく、ボタンでリンクする方法を紹介します。 

 link_toやurl_forを使えば、リンクを作成することはできると思いますが

ハイパーリンクではなくボタン形式でリンクを作成する方法です。

ボタンでリンクを作成する場合には

○button_to

を使用します。

 使い方は、link_toと同じです。

button_to(“更新”, :action =>’update’)

#=><form method “post” action=”/top/update” class=”button-to”>

       <div><input type=”submit” value”更新” /></div></form>

このbutton_toポイントとしては、

・formタグで作成されるので、既にformタグの中にいる場合は使えない

・当然ボタンによるリンクになる

・postメソッドが用いられるので、データの更新がある場合などのリンクに適している。

ということがあげられます。

今日は初歩的な内容でしたね。

でわでわまた。

Objective-C + Cocoaにおけるメモリ管理について

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回はObjective-CでCocoaアプリケーションを作る際における

メモリ管理について解説します。

http://farm4.static.flickr.com/3280/2987292642_b6d5e38a07.jpg

MyObject.h

#import <cocoa /cocoa.h>

// (1)
@interface MyObject : NSObject {
}

// (2)
-(void)dealloc;

@end

MyObject.m

#import "MyObject.h"

@implementation MyObject

// (3)
-(void)dealloc
{
	NSLog(@"MyObject dealloc");
	[super dealloc];
}

@end

Memory.m

#import <foundation /foundation.h>
#import "MyObject.h"

int main (int argc, const char * argv[]) {
    // (4)
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // (5)	
    MyObject* object1;
    object1 = [[MyObject alloc] init];
    [object1 release];

    // (6)
    MyObject* object2;
    object2 = [[[MyObject alloc] init] autorelease];

    // (7)	
    NSString* string0;
    string0 = [NSString stringWithCString:"new string" encoding:NSASCIIStringEncoding];

    // (8)	
    NSString* string1;
    string1 = [[[NSString alloc] initWithCString:"new string" encoding:NSASCIIStringEncoding] autorelease];

    // (9)	
    NSLog(@"before pool release");
    [pool release];
    NSLog(@"after pool release");

    return 0;
}

コード解説(1)

@interface MyObject : NSObject {
}

MyObjectクラスを宣言します。

NSObjectを親クラスとします。

コード解説(2)

-(void)dealloc;

deallocメソッドを宣言します。

このメソッドはインスタンス解放時に呼び出されます。

コード解説(3)

-(void)dealloc
{
	NSLog(@"MyObject dealloc");
	[super dealloc];
}

deallocメソッドを実装します。

NSLog関数にてメッセージを出力し、

親クラスであるNSObjectのdeallocを呼び出します。

コード解説(4)

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSAutoreleasePoolのオブジェクトを作成する。

この後に自動開放指定されたオブジェクトについては、

[pool drain] の時点で解放されます。

コード解説(5)

    MyObject* object1;
    object1 = [[MyObject alloc] init];
    [object1 release];

MyObjectオブジェクトのためのメモリを確保、

オブジェクトを初期化し、

解放します。

コード解説(6)

    MyObject* object2;
    object2 = [[[MyObject alloc] init] autorelease];

MyObjectオブジェクトのためのメモリを確保、

オブジェクトを初期化し、

自動開放指定します。

このオブジェクトは [pool drain] された時点で解放されます。

コード解説(7)

    NSString* string0;
    string0 = [NSString stringWithCString:"new string" encoding:NSASCIIStringEncoding];

NSStringオブジェクトのためのメモリを確保、

オブジェクトを初期化し、

自動開放指定します。

コード解説(8)

    NSString* string1;
    string1 = [[[NSString alloc] initWithCString:"new string" encoding:NSASCIIStringEncoding] autorelease];

NSStringオブジェクトのためのメモリを確保、

オブジェクトを初期化し、

自動開放指定します。

stringWithCString を用いる場合に比べてコードが冗長になりますので、

こういった場合は stringWithCString を呼び出した方が良いでしょう。

コード解説(9)

    NSLog(@"before pool release");
    [pool release];
    NSLog(@"after pool release");

NSAutoreleasePoolオブジェクトを解放する。

自動開放指定されたオブジェクトはこのタイミングでまとめて解放されます。

実行ログ

2008-10-30 12:15:01.597 Memory[6684:10b] MyObject dealloc
2008-10-30 12:15:01.598 Memory[6684:10b] before pool release
2008-10-30 12:15:01.599 Memory[6684:10b] MyObject dealloc
2008-10-30 12:15:01.600 Memory[6684:10b] after pool release

自動開放指定したオブジェクトが

[pool release] したタイミングで、

まとめて解放されていることが分かります。

さいごに

Objective-C + Cocoa のような参照カウント方式のメモリ管理では

オブジェクトの生存期間を意識しながらコードを書いていく必要があるかと思います。

次回以降、Objective-C や Cocoa に関する記事を掲載していきたいと思います。

お楽しみに!

個人ブログ 拡張現実ライフ

FireFoxでWebページの色を抜き出すアドオン

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Web制作ではよくお世話になるブラウザFireFox。

その中で、お手軽にWebページに使われる色を抜き出すアドオンを

ご紹介します。 

アドオン名はcolorzilla。

このアドオンを入れることによって簡単にWebページで気になる色を

取得することができます。

使い方は、まずはアドオンを入手しインストール。

インストールが済めば、ブラウザ上の左下にスポイトマークが表示されるはずです。

このスポイトマークをクリックすることで、即機能が使えます。

マウスカーソルが十字になったら、後は抜き出したい色に重ねてクリックしてください。

RGBでの数値や座標、HTMLタグがステータスバーに表示されるはずです。 

この状態で、スポイトを右クリックするとカラーコードをコピーしてくれる機能も

うれしいところ。

右クリックでさらに細かい機能も使うことができます。

Firebugでもソースコードからカラーコードを調べることはできますが、

colorzillaだと画像からも直接カラーコードを抜き出せるところが違います。

画像と同じ色で背景色を指定したい、などといった場合に重宝しますね。

Webカメラからの入力動画に対してActionScriptで2値化を行う

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回はActionScript3.0を使って、

Webカメラからの入力動画に対して2値化を行ってみます。

http://farm3.static.flickr.com/2284/2983782725_3acc71f952.jpg

ソースコード

package{
    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.system.*;
    import flash.text.*;
    import flash.geom.*;
    import flash.filters.*;

    [SWF(width="640", height="480")]

    public class Threshold2 extends Sprite {
	private var video:Video;
	private var camera:Camera;
	private var msg:String;
	public var txtArea:TextField = new TextField();
	public var bdTmp:BitmapData;
	public var bmp:Bitmap;

	public function Threshold2()
	{
	    stage.scaleMode = StageScaleMode.NO_SCALE;
	    stage.align = StageAlign.TOP_LEFT;

	    // (1)
	    camera = Camera.getCamera();
	    if(camera != null){
		camera.addEventListener(StatusEvent.STATUS, statusHandler);
		camera.setMode(640, 480, 15);
		camera.setMotionLevel(10);
		camera.setQuality(0, 50);

		// (2)
		video = new Video(camera.width, camera.height);
		video.attachCamera(camera);

		addEventListener(Event.ENTER_FRAME, tick);
	    }else{
		msg = "使用可能なカメラがありません。";
		txtArea.text = msg;
	    }

	    txtArea.autoSize = TextFieldAutoSize.LEFT;
	    txtArea.text = "Threshold";
	    txtArea.textColor = 0xffffff;
	    txtArea.x = 2;
	    txtArea.y = this.height - txtArea.textHeight - 10;
	    this.addChild(txtArea);

	    // (3)
	    bdTmp = new BitmapData(video.width, video.height, false, 0xffffff);
	    bmp = new Bitmap(bdTmp);
	    this.addChild(bmp);
	}

	private function statusHandler(evt:StatusEvent):void{
	    if(camera.muted){
		msg = "カメラへのアクセスが拒否されました。";
		msg += "カメラの映像を表示するにはアクセスを許可してください。";
		txtArea.text = msg;
		Security.showSettings(SecurityPanel.PRIVACY);
	    }else{
		msg = "使用中のカメラ : " + camera.name + "\n";
		msg += "幅x高さ : " + camera.width + "x" + camera.width;
		txtArea.text = msg;
	    }
	}

	private function tick(event:Event):void{
	    if(video == null || camera == null){
		return;
	    }
	    if(camera.muted == true){
		return;
	    }
	    // (4)
	    var s:BitmapData = new BitmapData(video.width, video.height);
	    s.draw(video);

	    // (5)
	    var r:Rectangle = new Rectangle(0, 0, video.width, video.height);
	    bdTmp.fillRect(r, 0xffffffff);

	    // (6)
	    var threshold:uint = 0x00800000;
	    var color:uint = 0x00000000;
	    var maskColor:uint = 0x00ff0000;
	    bdTmp.threshold(s, r, new Point(0, 0), "<=", threshold, color, maskColor, false);
	}
    }
}

コード解説(1)

camera = Camera.getCamera();

Webカメラに対して各種操作の行えるCameraオブジェクトを取得します。

コード解説(2)

video = new Video(camera.width, camera.height);
video.attachCamera(camera);

Webカメラからの入力映像をVideoオブジェクトに流し込みます。

コード解説(3)

bdTmp = new BitmapData(video.width, video.height, false, 0xffffff);
bmp = new Bitmap(bdTmp);
this.addChild(bmp);

画像操作用のバッファとしてBitmapDataオブジェクトを作成し、

Bitmapオブジェクトに関連づけて、画面に表示します。

コード解説(4)

var s:BitmapData = new BitmapData(video.width, video.height);
s.draw(video);

Webカメラからの入力をBitmapDataオブジェクトにコピーします。

コード解説(5)

var r:Rectangle = new Rectangle(0, 0, video.width, video.height);
bdTmp.fillRect(r, 0xffffffff);

処理対象の矩形をRectangleオブジェクトとして作成し、

BitmapDataオブジェクトの内容を白でクリアします。

コード解説(6)

var threshold:uint = 0x00800000;
var color:uint = 0x00000000;
var maskColor:uint = 0x00ff0000;
bdTmp.threshold(s, r, new Point(0, 0), "<=", threshold, color, maskColor, false);

thresholdメソッドを用いて2値化を行います。

対象のカラー要素をmaskColor(0x0ff0000)によって抽出し、

閾値threshold(0x00800000)より大きい場合は

ピクセル値color(0x00000000)に設定します。

さいごに

2値化には様々な方法があるのですが、

この記事では非常に簡単な方法を用いました。

ヒストグラムなどを作成した上でそれを元に2値化を行えば

より良い処理結果を得ることができます。

次回以降もActionScriptで様々な画像処理を紹介していきたいと思います。

お楽しみに!

個人ブログ 拡張現実ライフ

クローラー対策 ロボットテキスト (robots txt)

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちはカツオです。

今日はrobots.txtの書き方について説明します。

というのも

webサーバーでmongrelを使ったrailsアプリで、mongrelがよく落ちるのですが、

クローラーのアクセス数が多いので、

googleのクローラーをIPで制限してみたら、

mongrelの落ちる回数が、極端に減りました。

対策の一つとして、robots.txtを書く機会があったので、ご紹介です。  

■robots.txtとは?

クローラーや、スパイダー、検索ロボットといわれる
検索エンジンのインデックスを取得するために、web上を巡回しているソフトがあります。

もちろんそれらにアクセスされると、
検索エンジンのインデックスに登録される可能性があります。

しかし、サイトを運営していれば
インデックスされたくないページ等もあるでしょう。

そういったページ等をアクセスさせないよう命令するのが
robots.txtです。

■robots.txtの書き方
基本的にはrobotsテキストでは2つの命令がかけます。

1.アクセス制限
2.アクセス間隔の調整

上記2つです。

まずアクセス制限から説明します。

クローラーのアクセスを制限する場合
2種類の記述が必要です。

User-Agent:    命令の対象となるロボット
Disallow:    制限するページまたはディレクトリ

例)全てのロボットに、全てのページをインデックスさせない場合
User-Agent: *
Disallow: /

例)googleのクローラーから、testというディレクトリを制限する場合
User-Agent: Googlebot
Disallow: /test

例)yahooのクローラーから、「/test/index.html」というページを制限する場合
User-Agent: Slurp
Disallow: /test/(もしくは/test/index.html)

このような形で表記します。

例)複数のクローラーを制御する場合
1行あけて次のUser-Agentを書いてください。

User-Agent: Googlebot
Disallow: /test

User-Agent: Slurp
Disallow: /test/

例)複数の制限したいディレクトリがある場合
Disallowを行をあけずに書いてください。

User-Agent: *
Disallow: /test
Disallow: /demo

また、クローラーのアクセス間隔を指定する場合ですが
一度アクセスがあったら、次のアクセスまでに30秒間隔をあける場合は

○百度のクローラ
User-Agent:baiduspider
Crawl-Delay: 30

○yahooのクローラー
User-Agent:Slurp
Crawl-Delay:0.5
※yahooに関しては、単位が”分”らしいです。

○googleのクローラー
Crawl-Delayのコマンドにgoogleは対応していないので、
googleウェブマスターツールで
アカウント登録して、クローラーのアクセス頻度を下げるしかないようです。

■robots.txtの設置箇所

robots.txtの設置箇所はルートディレクトリと決められています。

弊社のURLの場合(http://www.kbmj.com/)

http://www.kbmj.com/robots.txt

このような階層に置かなければいけません。

※無料ブログの場合等は設置権限がない場合があります。

■robots.txtのファイル名

robots.txtのファイル名は間違えず、半角小文字で書きましょう

○ robots.txt

↓これは間違いです。

× robot.txt
× robots.text
× robots.txt

■補足
全てのクローラーがrobots.txtを読んでくれるわけではなく、
なかなか読んでくれないクローラーもあるようです。

ただ、もし、クローラーのアクセスでサーバー負荷が増えてしまっていたりする場合は、
一度試してみたら、いかがでしょう。

Railsでの画像の出力方法

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

どうも。

バッチです。 

今回のテーマは以外に忘れやすかったりする、

Railsで画像を出力する方法です。 
RailsでHTMLのIMGタグを出力するには、

<%= image_tag (“/images/hoge”) %>

と書きます。

ちなみにオプションを付ける場合は、

<%= image_tag (“/images/hoge”, :size=>”100×100″, :alt=>”画像”) %>

と書くことで、それに対応したHTMLが出力されます。

また、画像にリンクを張りたい場合は、

<%= link_to(image_tag(“/images/hoge”, :size=>”100×100″, :alt=>”画像”), {:controller => ‘hoge’, :action => ‘hoge’}) %>

といった感じで記述します。

紛らわしく、意外と忘れやすいので注意ですね。

Webカメラからの入力動画に対してActionScriptで色彩変換を行う

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回はActionScript3.0を使って、

Webカメラからの入力動画に対して色彩変換を行ってみます。

http://farm4.static.flickr.com/3236/2980918123_5fe237e523.jpg

ソースコード

package{
    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.system.*;
    import flash.text.*;
    import flash.geom.*;
    import flash.filters.*;

    [SWF(width="640", height="480")]

    public class Threshold extends Sprite {
	private var video:Video;
	private var camera:Camera;
	private var msg:String;
	public var txtArea:TextField = new TextField();
	public var bdTmp:BitmapData;
	public var bmp:Bitmap;

	public function Threshold()
	{
	    stage.scaleMode = StageScaleMode.NO_SCALE;
	    stage.align = StageAlign.TOP_LEFT;

	    // (1)
	    camera = Camera.getCamera();

	    if(camera != null){
		camera.addEventListener(StatusEvent.STATUS, statusHandler);
		camera.setMode(640, 480, 15);
		camera.setMotionLevel(10);
		camera.setQuality(0, 50);

		// (2)
		video = new Video(camera.width, camera.height);
		video.attachCamera(camera);

		addEventListener(Event.ENTER_FRAME, tick);
	    }else{
		msg = "使用可能なカメラがありません。";
		txtArea.text = msg;
	    }

	    txtArea.autoSize = TextFieldAutoSize.LEFT;
	    txtArea.text = "Threshold";
	    txtArea.textColor = 0xffffff;
	    txtArea.x = 2;
	    txtArea.y = this.height - txtArea.textHeight - 10;
	    this.addChild(txtArea);

	    // (3)
	    bdTmp = new BitmapData(video.width, video.height, false, 0xffffff);
	    bmp = new Bitmap(bdTmp);
	    this.addChild(bmp);
	}

	private function statusHandler(evt:StatusEvent):void{
	    if(camera.muted){
		msg = "カメラへのアクセスが拒否されました。";
		msg += "カメラの映像を表示するにはアクセスを許可してください。";
		txtArea.text = msg;
		Security.showSettings(SecurityPanel.PRIVACY);
	    }else{
		msg = "使用中のカメラ : " + camera.name + "\n";
		msg += "幅x高さ : " + camera.width + "x" + camera.width;
		txtArea.text = msg;
	    }
	}

	private function tick(event:Event):void{
	    if(video == null || camera == null){
		return;
	    }
	    if(camera.muted == true){
		return;
	    }

	    // (4)
	    bdTmp.draw(video);

	    // (5)
	    var rect:Rectangle = new Rectangle(bmp.width/2, 0, 
					       bmp.width/2, bmp.height);
	    var target:Point = new Point(bmp.width/2, 0);

	    // (6)
	    var filter:ColorMatrixFilter = new ColorMatrixFilter();
	    filter.matrix = new Array(1, 0, 0, 0);

	    // (7)
	    bdTmp.applyFilter(bdTmp, rect, target, filter);
	}
    }
}

コード解説(1)

camera = Camera.getCamera();

Webカメラに対して各種操作の行えるCameraオブジェクトを取得します。

コード解説(2)

video = new Video(camera.width, camera.height);
video.attachCamera(camera);

Webカメラからの入力映像をVideoオブジェクトに流し込みます。

コード解説(3)

bdTmp = new BitmapData(video.width, video.height, false, 0xffffff);
bmp = new Bitmap(bdTmp);
this.addChild(bmp);

画像操作用のバッファとしてBitmapDataオブジェクトを作成し、

Bitmapオブジェクトにひも付け、画面に表示します。

コード解説(4)

bdTmp.draw(video);

Videoオブジェクトの内容をBitmapDataオブジェクトにコピーします。

コード解説(5)

var rect:Rectangle = new Rectangle(bmp.width/2, 0, 
                                   bmp.width/2, bmp.height);
var target:Point = new Point(bmp.width/2, 0);

フィルタを適用するための矩形と座標を決定します。

コード解説(6)

var filter:ColorMatrixFilter = new ColorMatrixFilter();
filter.matrix = new Array(1, 0, 0, 0);

画素に対して変換を施すためのフィルタを作成し、

そのフィルタで用いる変換用の行列を設定します。

これは各ピクセルのRGBAカラー値に対して適用するための4×5行列であり、

これによって新しいRGBAカラー値を得ることができます。

コード解説(7)

bdTmp.applyFilter(bdTmp, rect, target, filter);

BitmapDataオブジェクトに対してフィルタを適用します。

この際、矩形と座標も同時に指定します。

さいごに

ColorMatrixFilterを使えば、

彩度変更、色相回転、輝度アルファ変換など、各種効果を汎用的に施すことができます。

皆さんも是非試してみて下さい。

個人ブログ 拡張現実ライフ

Webカメラからの入力に対してActionScriptでエッジ検出を行う

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは。

KBMJの佐藤です。

今回はActionScriptを使って、

Webカメラからの入力に対してエッジ検出を行ってみます。

http://farm4.static.flickr.com/3022/2977769785_fc19b82eea.jpg

ソースコード

package
{
    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.filters.*;

    public class Motion extends Sprite {
	private var bd:BitmapData;
	private var video:Video;
	private var bitmap:Bitmap;

	public function Motion(){
	    // (1)
	    bd = new BitmapData(640, 480, false, 0x00000000);
	    bitmap = new Bitmap(bd);
	    addChild(bitmap);
	    addEventListener(Event.ENTER_FRAME, onEnterFrame);

	    // (2)
	    var camera:Camera = Camera.getCamera();

	    if(camera != null){
		video = new Video(640, 480);
		video.attachCamera(camera);
	    }
	}
        public function onEnterFrame(evt:Event):void {
	    // (3)
	    bd.draw(video);
	    var conv:ConvolutionFilter;
	    var edges:Array = [0, -1, 0,
                               -1, 4, -1,
                               0, -1, 0];
	    convFilter(bitmap, edges, 1);
        }
        private function convFilter(dispObj:DisplayObject, m:Array, d:int):void{
	    // (4)
	    var conv:ConvolutionFilter = new ConvolutionFilter(3, 3, m, d);
	    dispObj.filters = [conv];
	}
    }
}

コード解説(1)

bd = new BitmapData(640, 480, false, 0x00000000);
bitmap = new Bitmap(bd);
addChild(bitmap);

ここではWebカメラからの入力を描画するためのBitmapDataオブジェクトを生成しています。

ActionScriptではBitmapDataオブジェクトを用いることによって、

ビットマップを直接操作することができます。

コード解説(2)

var camera:Camera = Camera.getCamera();

if(camera != null){
    video = new Video(640, 480);
    video.attachCamera(camera);
}

Cameraオブジェクトを取得し、

そこからの入力をVideoオブジェクトに割り当てています。

コード解説(3)

    bd.draw(video);
    var conv:ConvolutionFilter;
    var edges:Array = [0, -1, 0,
                       -1, 4, -1,
                       0, -1, 0];
    convFilter(bitmap, edges, 1);

Videoオブジェクトの内容をBitmapオブジェクトに描画しています。

畳み込みフィルタの内容を配列で作成し、

Bitmapオブジェクトに設定しています。

コード解説(4)

    // (4)
    var conv:ConvolutionFilter = new ConvolutionFilter(3, 3, m, d);
    dispObj.filters = [conv];

ConvolutionFilterオブジェクトを生成して

畳み込みフィルタの配列を適用しています。

filtersとあるように、フィルタは複数設定することができます。

さいごに

ActionScriptはWebブラウザ上で実行でき、

なおかつリッチなプレゼンテーションが得意なので、

グラフィック処理を色々と試してみるには良いプラットフォームだと思います。

皆さんも是非試してみて下さい。

個人ブログ 拡張現実ライフ

最近人気な記事