65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Django 中使用 Linux 应用程序处理图像

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2019 年 7 月 16 日

CPOL

4分钟阅读

viewsIcon

6063

在Django中运行命令行Linux应用程序以快速处理360度图像。

引言

图片来自:ikoma360

使用Linux图像处理应用程序与Django结合,提供了一种快速原型设计和与开发或业务团队分享想法的方法。本文介绍了如何从360°图像中提取EXIF元数据并应用水印。虽然示例图像是用理光THETA相机拍摄的,但这些技术应该适用于任何能够拍摄360°图像的相机。

本文中的示例重点介绍在服务器上运行的常用Linux应用程序exiftool和ImageMagick。您也可以在Linux工作站的命令行上使用这些工具。这允许摄影师和所有非开发人员协助测试不同的技术。

您可以在这里查看本文中创建的水印的360度图像演示。使用鼠标单击并拖动图像向上、向下、向左、向右。

背景

这是文章使用Django和A-Frame的360图像网络画廊的续篇。360图像的显示和处理与普通JPEG图像略有不同。上一篇文章重点介绍了360图像的显示。本文展示了使用Django和命令行工具的简单处理技术。

360图像采用等矩形格式,并依赖于元数据或EXIF数据来显示方向。以下是藤田豊(Toyo Fujita)使用理光THETA Z1拍摄的DNG/RAW图像的示例数据,这些数据在导出到JPG之前使用供应商的软件拼接成等矩形格式。

Full Pano Height Pixels : 3584 
Full Pano Width Pixels : 7168 
Initial Horizontal FOV Degrees : 70.0 
Initial View Heading Degrees : 0.0 
Initial View Pitch Degrees : 0.0 
Initial View Roll Degrees : 0 
Pose Heading Degrees : -54.1 
Pose Pitch Degrees : 0.0 
Pose Roll Degrees : 0.0 
Projection Type : equirectangular 
Stitching Software : RICOH THETA Stitcher v1.00.4 
Use Panorama Viewer : true 

除了方向信息外,如果使用了GPS单元,EXIF数据还将包含位置信息。

Date/Time Created : 2019:07:06 08:58:29-08:58 
GPS Altitude : 43 m Above Sea Level 
GPS Date/Time : 2019:06:17 19:59:06Z 
GPS Latitude : 34 deg 40\' 5.20" N 
GPS Latitude Ref : North 
GPS Longitude : 135 deg 26\' 15.80" E 
GPS Longitude Ref : East 
GPS Position : 34 deg 40\' 5.20" N, 135 deg 26\' 15.80" E 
Image Size : 7168x3584 
Megapixels : 25.7 
Shutter Speed : 1/13 

提取EXIF数据 - 简单示例

您可以使用名为exiftool的免费工具轻松抓取和修改EXIF数据。

$ exiftool filename.jpg

在Django的`views.py`文件中,您可以使用`subprocess`直接访问Linux命令。

在下面的示例中,我已经将图像文件的完整路径写入代码中。在生产环境中,您需要从您的文件上传代码中获取此路径。

通过PIPE推送`stdout`,您可以将输出返回到Django。

from django.shortcuts import render
from subprocess import Popen, PIPE, STDOUT

def homepage(request):
    # pass in file name after upload for production
    image_file_name = "/home/craig/Development/django/shell/shell/media/osaka-night.jpg"
    process = Popen(['exiftool', image_file_name], stdout=PIPE, stderr=STDOUT)
    output_byte = process.stdout.read()
    output_list = str(output_byte)[2:-1].strip().split('\\n')
    return render(request, 'home.html', 
    {"output": output_list, "filename": image_file_name.split('/')[-1]})

输出作为`render`的第三个参数传递给HTML模板。数据作为字典发送。在此示例中,字典的值是一个列表。在HTML中,只需使用`for`循环迭代列表即可。`{% for line in output %}`部分是如何将数据导入HTML。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/0.7.1/aframe.min.js" 
crossorigin="anonymous"></script>
<style>
a-scene {
height: 400px;
width: 100%;
}

</style>
<title>EXIF Data extraction</title>
</head>
<body>
<h1>RICOH THETA exif output</h1>
  <a-scene embedded>
     <a-sky src="/media/{{filename}}" rotation="0 -130 0"></a-sky>
  </a-scene>

{% for line in output %}
    {{ line }}
    <br >
{% endfor %}

</body>
</html>

上面的示例使用A-Frame来显示和导航360图像。

添加水印 - 更复杂的示例

此示例使用ImageMagick添加水印。它采用两张图像并将它们合并到第三张图像中。第三张图像的位置传递给HTML模板文件,以便使用A-Frame进行渲染。

`composite`工具是ImageMagick的一部分。命令行序列是:

$ composite -geometry +3000+1600 theta_logo.png toyo-hardrock.jpg new-image.jpg

为了使它与subprocess Popen一起工作,您将命令和参数放在一个列表中,并将列表传递给Popen。

def watermark(request):
    # pass in file name after upload for production
    image_file_name = "/home/craig/Pictures/theta/2019/watermark/toyo-hardrock.jpg"
    logo_file_name = "/home/craig/Pictures/theta/2019/watermark/theta_logo.png"
    output_file = "/home/craig/Development/django/shell/shell/media/new-image.jpg"
    # composite is part of imagemagick package
    Popen(['composite', '-geometry', '+3000+1600', logo_file_name,
        image_file_name, output_file], stdout=PIPE, stderr=STDOUT)

    return render(request, 'watermark.html', {"output": output_file.split('/')[-1]})

水印是`theta_logo.png`。它是一个具有40%透明度的PNG文件。ImageMagick能够将其与JPG文件合并。

HTML更简单。它只是使用传递给它的文件位置显示图像。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>watermark</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/0.7.1/aframe.min.js" 
    crossorigin="anonymous"></script>
</head>
<body>
    <h1>Watermark</h1>

    <a-scene>
            <a-sky src="/media/{{output}}" rotation="0 -130 0"></a-sky>
          </a-scene>
    
</body>
</html>

我将水印设置在等矩形图像的中心。

您还可以创建更大的蒙版并将两张图像合并。

创建一个与原始图像大小相同的蒙版。将其放置在0, 0处。

实时示例

您可以对所有图像使用相同的蒙版模板。由于蒙版嵌入到图像本身中,因此盗窃的风险很小。

关注点

虽然这取决于个人喜好,但在后端使用Python比使用JavaScript更令人愉快。与JavaScript MEAN堆栈相比,Django被认为比较旧,但它超级快速,并且在一小时内就能轻松完成一些工作。如果您想要更快的速度,可以在Python中使用Linux命令。您也可以将多个Linux命令放在bash脚本中,然后从Django内部运行该脚本。是的,这是一个技巧,但有时您只想快速展示一些东西。

迁移到生产环境

原型设计完成后,您应该使用Python或C库来处理Django中的图像。一个通用的Python图形库是Pillow

更多测试、信息和实验

此测试中使用的代码可在GitHub上获得

我们很多人都在测试将Django与360图像一起使用。查看最新的讨论在这里

历史

  • 2019 年 7 月 16 日:初始版本
© . All rights reserved.