プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

フォトグラメトリーやってみた

子どもが夏休みの宿題で、工作というか駅の模型を作りました。

市内の近鉄宇治山田駅です。

親(バカ)的には頑張ったなという感じなんですが、いかんせん、段ボール工作なので、そのうち壊れるのが目に見えてます。実際、持ち帰ってくるときに既に一部破損しました。

ふと、せっかくなので壊れてしまう前に、3Dモデルにしておいたらどうだろうか?と思いつきました。最近の iPhone PRO版 だと LiDAR 搭載で、 3D スキャンできるけど、 Androidってできないよな?と思いつつ、たしか、複数の写真から 3D モデル作る方法があったよなって、調べると、『フォトグラメトリー』と呼ぶそうです。

ということで、試しにやってみたので、メモっておきます。

ã‚„ã‚Šæ–¹

まずはネットをググると、ちょうどよさそうな記事がいくつも見つかりました。

なるほど。いまや、スマホのアプリで簡単にできるようです。アプリもいくつかあるようですね。Google アカウントですぐに使えるので、今回は Polycam というやつを使うことにしました。

poly.cam

写真の撮影と 3D モデルの作成

Polycam をスマホにインストールして立ち上げます。ログインするように求められるので、 Google アカウントでログインします。

次に、早速モデルを撮影します。写真が 20 枚あれば、3Dモデルを作ってくれるそうです。無料版だと最大 100 枚だそうです。

こんな感じに、とりあえず、あちこちの角度から撮ってみます。ある程度撮れたな?と思ったら、『DONE』のボタンを押すと、

と表示されるので、デフォルトの設定のまま、『UPLOAD & PROCESS』ボタンを押すと、写真がアップロードされて、 3D モデルが作成されます。

しばらく(数分ぐらい?枚数でも変わるっぽいです)すると、3Dモデルができました。いや、すごいな、これ。

poly.cam

一度モデルができると、スマホアプリでも、PCのブラウザでもアクセスできるようになります。リンク貼っておくので、ご興味のある方は一度見てみてください。

公開方法

なお、上記にリンクを貼りましたが、作成した 3D モデルはリンクを知っている人にはいつでも公開することができるようです。有料版だと、個別のユーザー限定での公開もあるようです。

また、それとは別で、『Publish』とすると、データを Polycam 内で公開して、 Polycam 内で共有することができるそうです(『Explore』と呼んでいる機能みたい)。

データのダウンロード

作成した 3D データはダウンロードもできるようです。PC版(ブラウザ)の場合だと、

右上にある『Download』ボンタンを押すと、

のようにフォーマットの選択画面が表示されます。ほとんどが『PRO』のラベルがついているので、有料になるのかな?と思いきや、『gltf』にはマークがついていません。

Polycam の説明などをみると、作成したデータのダウンロード(エクスポート)には有料プランが必要とあるのですが、フォーマットが gltfだと無料版でもいけそうですね。

ということで、『gltf』を選択して、『EXPORT』ボタンを押すと、おぉ、ちゃんとダウンロードされました。

ダウンロードすると glb という拡張子のファイルが保存されました。glTFのバイナリー版だそうです。

確認

ダウンロードしたファイルをどうやって確認しようかな?と考えてネットを探すと、 gltf/glb を表示してくれるサイトがありました。

glTF Viewer

ここにダウンロードしたファイルをドラッグ&ドロップすると、ちゃんと表示されました。

ちなみに、下記の記事などをみると、VSCode でも表示することができるようです。こんどやってみようかな。

glTFの確認手段 – ft-lab

それにしても、3Dモデルをマウスで操作するの難しいですね。なかなか思うような向きに変えることができません。このあたり、もっと直観的にできるようになるといいんでしょうね。

アプリについて

Polycam 簡単にフォトグラメトリができていいですね。ただ、気になる点もいくつかありました。

まず、何度か試していると、写真アップロード後の processing のあとに failed となることがありました。ただ、画面上には理由などが出てこないので、なぜ失敗したのかがわからないのがちょっと残念なところですね。まあ、理由書かれても対応むずかしいような気もしますので、致し方ないのでしょうが。

あと、フォトグラメトリが月に 5 件できるとあるのですが、アプリ上ではなにやら別のカウンタもあり、これが何を意味しているのかがちょっと分からないです。両者に関係があるのかどうかも不明。このあたりがもうちょっとわかりやすいといいですよね。

アプリの表示は英語のみみたいです。日本語への切り替えとかできるとこの分野に慣れていない人間にも使いやすいのにな、と思います。

所感

今回の撮影対象は段ボールということもあり、3D モデルはできるんだけど、一部が抜けていたり、うまく全体をモデル化するのが意外と難しかったです。何も考えずにやった一番最初のが結構よかったりしました。

いろいろと試した印象では、写真の枚数が多ければいいというものでもなさそうだし、近すぎる写真が多くても平板になって背景として扱われるのかやはりうまくモデル化できない感じでした。撮影した部屋に窓があって、昼間だと外の光が意外と明るくて、逆光気味の写真になるのも影響してるような気がします(夜に蛍光灯の下でやったときのほうがいい感じでした)。もろもろ、このあたりもテクニックがあるんだろうなと感じてます。

最終的には、上にあげたものになったんですが、一番上のアンテナみたいなのは結局うまくモデル化できませんでした。全体に対して線が細すぎるから除外されるんでしょうね、たぶん。このたりもフォトグラメトリの限界なのかな?

とはいうものの、 Android でしかも無料のアプリをインストールするだけで簡単に3Dモデルを作れるのはなかなかいいですね。ちょっと遊んでみようと思います。

SAM で Lambda 関数のみのアプリケーションをデプロイ

AWS Toolkit または SAM CLI を使って、Lambda 関数をデプロイできるようになりました。

次は、 API Gateway + Lambda の Hello World のサンプルから一歩進めて、 Lambda 関数のみの構成をデプロイしてみます(進んでんのか?)。

  • WSL, Ubuntu 24.04.1
  • SAM CLI 1.131
  • AWS CLI 2.2.42

SAM CLI でのアプリケーション作成

VSCode の SAM アプリケーションの新規作成では、 Lambda 関数のみのテンプレートがないので、コマンドラインから実行します。

mor@DESKTOP-DE7IL4F:~/tmp/sam_samples$ sam init

You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Data processing
        3 - Hello World Example with Powertools for AWS Lambda
        4 - Multi-step workflow
        5 - Scheduled task
        6 - Standalone function
        7 - Serverless API
        8 - Infrastructure event management
        9 - Lambda Response Streaming
        10 - Serverless Connector Hello World Example
        11 - Multi-step workflow with Connectors
        12 - GraphQLApi Hello World Example
        13 - Full Stack
        14 - Lambda EFS example
        15 - DynamoDB Example
        16 - Machine Learning
Template: 6

SAM CLI であれば、『Standalone function』が選択できます。しかし、

Which runtime would you like to use?
        1 - dotnet8
        2 - dotnet6
        3 - nodejs22.x
        4 - nodejs20.x
        5 - nodejs18.x
        6 - nodejs16.x
Runtime: ^CAborted!

mor@DESKTOP-DE7IL4F:~/tmp/sam_samples$

なんとこの場合、ランタイムは dotnet と Node.js のみです。Python がない。なんとまあ。

Hello World サンプルからの作成

そこで、世の中の人はどうしているのか調べてみると、

などの記事が見つかります。

要は、 Hello World のテンプレートで新規アプリケーションを作成して、 API Gateway に関する記述を削除する、というやり方ですね。

ということで、やってみます。

まずは、 Hello World アプリケーションを作成します。VSCode でもコマンドラインでもお好きなほうで OK です。ランタイムは Python を選んでおきます。アプリケーションができたら、 template.yaml を編集します。

変更前

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-lambda-only

  Sample SAM Template for sam-lambda-only

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.13
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /hello
            Method: get

Outputs:
  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
  # Find out more about other implicit resources you can reference within SAM
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

変更後

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-lambda-only

  Sample SAM Template for sam-lambda-only

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  LambdaOnlyFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      FunctionName: "lamuda-only"
      Description: "sample lambda function only application created by SAM"
      CodeUri: lambda-src/
      Handler: app.lambda_handler
      Runtime: python3.13
      Architectures:
        - x86_64
#      Events:
#        HelloWorld:
#          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
#          Properties:
#            Path: /hello
#            Method: get

#Outputs:
#  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
#  # Find out more about other implicit resources you can reference within SAM
#  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
#  HelloWorldApi:
#    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
#    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
#  HelloWorldFunction:
#    Description: "Hello World Lambda Function ARN"
#    Value: !GetAtt HelloWorldFunction.Arn
#  HelloWorldFunctionIamRole:
#    Description: "Implicit IAM Role created for Hello World function"
#    Value: !GetAtt HelloWorldFunctionRole.Arn

のようにしました。主な変更点としては、

  • Resources の 論理名を HelloWorldFunction から LambdaOnlyFunction に変更
  • Resources の LambdaOnlyFunction 定義の Properties に FunctionName と Description を追加
  • Resources の LambdaOnlyFunction 定義の Properties の CodeUri を適切な名前に変更
  • Resources の LambdaOnlyFunction 定義の Events 以下を削除
  • Outputs を無くす

としました。

1つ目の Resources の HelloWorldFunction の部分は、論理名として扱われるとのことなので、わかりやすい名前に変えてみました。

また、3つ目の CodeUri ですが、SAMで扱う分には、関数本体のファイルがあるフォルダを指せばよさそうです。

この変更に伴い、ローカルのフォルダ名も lambda-src に変更しました。

4つ目の Events の記述があることで API Gateway のリソースが作成されるので、ここを削除しています。

あと、デプロイは VSCode でやるつもりなんですが、この場合デフォルトだと S3 バケットにフォルダが作られないので、 samconfig.toml に s3_prefix を追加しておきます。

アプリケーション作成直後

[default.deploy.parameters]
capabilities = "CAPABILITY_IAM"
confirm_changeset = true
resolve_s3 = true

s3_prefix を追加

[default.deploy.parameters]
capabilities = "CAPABILITY_IAM"
confirm_changeset = true
resolve_s3 = true
s3_prefix = "lambda_only_sample"

デプロイ

これで一度デプロイしてみます。デプロイは、 VSCode からやってみました。

こんな感じで問題なくデプロイできますね。なお、 Outputs がないため、画面に ARN 等が表示されていないことがわかります。こちらの記事だと、 Outputs を無くせなかったとあったのですが、 SAM CLI のバージョンアップに伴い仕様が変わったんですかね?今はなくしても問題ないようです。

aws 側も確認してみます。

CloudFormation の sam-lambda-only スタックを表示すると

こんな感じになり、 Lambda と IAM Role のみが作成された形になっています。また、この論理ID(論理名)が、先ほど template.yaml で変更した LambdaOnlyFunction に対応するものになっていることもわかります。

Lambda を見てみると、

関数名が FunctionName で指定した lamuda-only になっていることがわかります(間違えたつづりにしています)。API Gateway がないこともわかります。また、追加した Description も反映されています。

ただ、残念ながら、 samconfig.toml に設定した s3_prefix は消えてました。デプロイ時に samconfig.toml を書き換えるためなんでしょうね、きっと。このため、 S3 バケットの直下にファイルがアップロードされたようです。

なお、一度デプロイに成功したら、 s3_prefix を追加してデプロイしても『Use default values from samconfig』を選べば反映されました。

テスト

大丈夫だと思いますが、テストしておきます。

VSCode のサイドパネルから aws を選び、 Explorer で Lambda 関数を表示させます。

ここで、実行ボタン(横向き△のボタン)にマウスをホバーさせると『Invoke in the cloud』とあるので、これをクリックすることで、 aws 側の関数を呼び出すことができそうです。

やってみます。実行ボタンを押すと、

のような画面が表示されます。今回は payload に何も指定せず、そのまま『Remote Invoke』ボタンを押します。

するとこんな感じで応答が出力されました。CloudWatch ログにも実行したログが残ってますし、大丈夫そうですね。

VSCode の AWS Toolkit でデプロイに失敗

こちらの一連の記事で AWS Toolkit を試した際は、コマンドラインでデプロイしてました。なので、1本目の記事で VSCode でプロファイルを指定したのですが、何に使うのこれ?って感じでした。

アプリケーションの新規作成からデプロイまでの一連の作業は VSCode からでもできるはずです(でないと AWS Toolkit のメリットがいまいちですからね)。で、調べると、下記の記事などが見つかったので、これを参考にして次は VSCode 上でのデプロイを試してみます。

AWS Toolkit for Visual Studio Code試す #AWS - Qiita

新規アプリケーション作成

まず、新規にアプリケーションを作成するところからやってみます。VSCode を開いて、サイドパネルから aws タブを選んで、

Explorer の3点メニューから『Create Lambda SAM Application』を選択します。

すると『Select a SAM Application Runtime』としてランタイムを効かれるので、今回も Python 3.13 を選びます。次に、

のようにテンプレートの選択になります。この選択肢が、コマンドラインの sam init に比べて少ないんですね。今回はここでも、 Hello World を選びます。

次は、『Select the folder for your new SAM application』となり、作成するアプリケーションを保存するフォルダの選択を行います。この時表示されている sam_samples というのは、いま VSCode で開いているフォルダなので、ここをそのまま選びます。

フォルダを選択すると、アプリケーション名の入力になるので、適当な名前を入れます。

アプリケーション名(ここでは『third-sample』としました)入力後、 Enter キーを押すと、アプリケーションが作成されます。

こんな感じに、さきほど指定したフォルダの配下に、アプリケーション名のフォルダを作成し、その内部にファイル一式が作られます。

デバッグ

デバッグもこのままできます。既に、アプリケーション名のフォルダの上に .vscode フォルダと内部に launch.json が作られています。中身をみると、

{
    "configurations": [
        {
            "type": "aws-sam",
            "request": "direct-invoke",
            "name": "third-sample:HelloWorldFunction (python3.13)",
            "invokeTarget": {
                "target": "template",
                "templatePath": "${workspaceFolder}/third-sample/template.yaml",
                "logicalId": "HelloWorldFunction"
            },
            "lambda": {
                "payload": {},
                "environmentVariables": {},
                "runtime": "python3.13"
            }
        },
        {
            "type": "aws-sam",
            "request": "direct-invoke",
            "name": "API third-sample:HelloWorldFunction (python3.13)",
            "invokeTarget": {
                "target": "api",
                "templatePath": "${workspaceFolder}/third-sample/template.yaml",
                "logicalId": "HelloWorldFunction"
            },
            "api": {
                "path": "/hello",
                "httpMethod": "get",
                "payload": {
                    "json": {}
                }
            },
            "lambda": {
                "runtime": "python3.13"
            }
        }
    ]
}

のように、以前やったときと同様のデバッグ構成が記入済みになっています。

実際にブレークポイントを設定して実行すると問題なく動きました。

デプロイ

サイドパネルの aws タブの『Application Builder』を開きます。

いま VSCode で開いているフォルダに複数のアプリケーションがある場合は、アプリケーション名が並んでいるので、今回作成したアプリケーションを選択します。一番右の雲のアイコン、『Deploy SAM Application』アイコンをクリックします。なお、コマンドパレットを開いて、コマンドパレットから、 AWS: Deploy SAM Applocation を選択しても呼び出すことができます。

最初のデプロイコマンドの選択では『Deploy』を選択します。すると、いくつかパラメータの入力を求められます。

まずは入力したパラメータを保存したいので『Specify required parameters and save as defaults』を選択します。次に、

一覧よりデプロイするリージョンを選択します。

その次に、 CloudFormation スタックの一覧が表示されるので、既存のものを選択するか

新規に作成する場合は、入力します(ここでは、『third-sample』としました)。

次に、 S3 バケットの選択画面になります。こちらの記事をやったときに S3 バケットは作成済みなので『Specify an S3 bucket』を選択します。

一覧が表示されるので、こちらの記事で作られたバケット(一番下)を選んでおきます。

バケットを選ぶとデプロイが始まります。

が、なんと、ここでエラーがでました。

エラーの部分だけ取り出すと

Error: Cannot use both --resolve-s3 and --s3-bucket parameters in non-guided deployments. Please use only one or use the --guided option for a guided deployment.

ということのようです。どうしよう・・・

エラーへの対応

改めてエラーの内容を読んでみると non-guided では、 --resolve-s3 と --s3-bucket を同時に指定することができなくて一方だけにしろ、ということだとわかります。

コマンドラインでデプロイするときにオプションで付けていた --guided が対話的におこなうやつだったので、 non-guided は非対話的におこなうデプロイ方法なんでしょうね。で、 VSCode からはこっちの non-guided で呼ばれているんでしょうね、きっと。

オプションが書いてあると思われる samconfig.toml を見てみると、

[default.deploy.parameters]
capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"]
confirm_changeset = false
resolve_s3 = true
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxx"

という記述があります。一度 s3_bucket の行を消してやり直しても、やはりエラーになります(ついでに、s3_bucket の行も復活してます)。

どうすればいいんだ?

解決

ふと、 resolve-s3 は自動的にS3のバケットを作成するというオプションなので、ひょっとしたらデプロイ時のS3の選択時のところで、

もう一方の『Create a SAM CLI managed S3 bucket』のほうを選んでみたらいいんじゃないか?

と思って、 samconfig.toml から s3_bucket の記述を削除してから、これで試してみると、あら不思議

ビルドが成功しました。

ということで『Create ~』のほうは、resolve-s3 オプションを指していて、バケットがなければ作るしあればそれを利用するというオプションなんだと思います、きっと。

デプロイ2回目

ちなみに、2回目のデプロイ時は、

のように、『Use default values from samconfig』という、既存の samconfig ファイルを指定できるオプションが増えていました。これを選べば、面倒なパラメータの指定が要らないので、楽ですね。

(参考) samconfig.toml の違い

コマンドラインからデプロイしたときと VSCode からデプロイしたときで、保存された samconfig.toml は若干違っているようです。

左がコマンドライン時のもの、右が VSCode のものになります。

VSCode だと別途プロファイルを指定して接続しているので、 profile の記述がいらないなどあるんでしょうね。

あと、VSCode でデプロイした場合、 S3 のバケット内にスタック名のフォルダが作られず、バケット直下にファイルが作られていました。それもこの s3_prefix の有無と関係がありそうですね。

大きくは異ならないようですが、一応こんな違いがありました。ま、このあたりは SAM 使いながら理解していきましょう。

所感

ということで、コマンドラインでのデプロイに加えて、 VSCode からのデプロイも試してみました。どちらでも操作できるのいいですね。