FFMPEG 旋转图片

11
我正在尝试使用FFMPEG批量调整图像大小,我已经成功地在bash中完成了这个任务,但我注意到一些竖向的图像被旋转成了横向。 这是原始图像,但是如下所示,它会被旋转。

Rotated image

正如您在上面看到的那样,图像被旋转了。起初,我认为这是由于我使用的-vf scale标志来调整图像大小,但我尝试了以下命令,它仍然旋转了图像。
ffmpeg -i input.jpg output.jpg

这并不是每张图片都会发生的事情,甚至不是所有肖像图片都会出现。此外,有些图片顺时针旋转,而有些则逆时针旋转。这不是随机事件,所有最初旋转的图片无论我运行多少次命令都会继续旋转。 控制台输出
ffmpeg version N-79942-gdc34fa6-tessus Copyright (c) 2000-2016 the FFmpeg developers
  built with Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
  configuration: --cc=/usr/bin/clang --prefix=/opt/ffmpeg --as=yasm --extra-version=tessus --enable-avisynth --enable-fontconfig --enable-gpl --enable-libass --enable-libbluray --enable-libfreetype --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopus --enable-libschroedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzmq --enable-version3 --disable-ffplay --disable-indev=qtkit --disable-indev=x11grab_xcb
  libavutil      55. 23.100 / 55. 23.100
  libavcodec     57. 38.100 / 57. 38.100
  libavformat    57. 35.100 / 57. 35.100
  libavdevice    57.  0.101 / 57.  0.101
  libavfilter     6. 44.100 /  6. 44.100
  libswscale      4.  1.100 /  4.  1.100
  libswresample   2.  0.101 /  2.  0.101
  libpostproc    54.  0.100 / 54.  0.100
Input #0, image2, from '/Users/jaketr00/Desktop/IMG_1902.JPG':
  Duration: 00:00:00.04, start: 0.000000, bitrate: 1025494 kb/s
    Stream #0:0: Video: mjpeg, yuvj422p(pc, bt470bg/unknown/unknown), 5184x3456, 25 tbr, 25 tbn
[image2 @ 0x7ff751803e00] Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
Output #0, image2, to '/Users/jaketr00/Desktop/IMG_19022.JPG':
  Metadata:
    encoder         : Lavf57.35.100
    Stream #0:0: Video: mjpeg, yuvj422p(pc), 5184x3456, q=2-31, 200 kb/s, 25 fps, 25 tbn
    Metadata:
      encoder         : Lavc57.38.100 mjpeg
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
Stream mapping:
  Stream #0:0 -> #0:0 (mjpeg (native) -> mjpeg (native))
Press [q] to stop, [?] for help
frame=    1 fps=0.0 q=8.2 size=N/A time=00:00:00.04 bitrate=N/A speed=0.0753x   frame=    1 fps=0.0 q=8.2 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=0.0752x    
video:554kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

有没有办法阻止这种情况发生?


你能提供一个样本文件吗? - llogan
@LordNeckbeard 我已经尝试了,但正如我在问题中所述,所有的图片都超过2MB,所以我无法上传它们。 - ZomoXYZ
请使用Google Drive、Dropbox或其他(合理的)文件托管服务。 - llogan
1
如果您使用 JPG 图像,则它们包含一个 EXIF 方向标志。一些软件,如 ImageMagick,可以被告知纠正旋转。其他软件,例如您所使用的软件,没有自动定向以校正旋转标志。 - fmw42
7个回答

5
我遇到了同样的问题,并意识到在使用ffmpeg时,图像的方向标签没有被保留。 原始图片
$ exiftool -Orientation input.jpg 
Orientation                     : Rotate 90 CW

完整输出:
$ identify -verbose input.jpg 
Image: input.jpg
  Format: JPEG (Joint Photographic Experts Group JFIF format)
  Mime type: image/jpeg
  Class: DirectClass
  Geometry: 4160x3120+0+0
  Resolution: 72x72
  Print size: 57.7778x43.3333
  Units: PixelsPerInch
  Colorspace: sRGB
  Type: TrueColor
  Base type: Undefined
  Endianess: Undefined
  Depth: 8-bit
  Channel depth:
    Red: 8-bit
    Green: 8-bit
    Blue: 8-bit
  Channel statistics:
    Pixels: 12979200
    Red:
      min: 0  (0)
      max: 255 (1)
      mean: 108.185 (0.424255)
      standard deviation: 61.0896 (0.239567)
      kurtosis: -0.901126
      skewness: -0.248333
      entropy: 0.945001
    Green:
      min: 0  (0)
      max: 255 (1)
      mean: 105.661 (0.414356)
      standard deviation: 60.1866 (0.236026)
      kurtosis: -0.9917
      skewness: -0.0344804
      entropy: 0.963995
    Blue:
      min: 0  (0)
      max: 255 (1)
      mean: 93.8873 (0.368186)
      standard deviation: 63.4227 (0.248716)
      kurtosis: -1.00629
      skewness: 0.325207
      entropy: 0.958324
  Image statistics:
    Overall:
      min: 0  (0)
      max: 255 (1)
      mean: 102.578 (0.402265)
      standard deviation: 61.5663 (0.241436)
      kurtosis: -1.03922
      skewness: 0.0137682
      entropy: 0.955774
  Rendering intent: Perceptual
  Gamma: 0.454545
  Chromaticity:
    red primary: (0.64,0.33)
    green primary: (0.3,0.6)
    blue primary: (0.15,0.06)
    white point: (0.3127,0.329)
  Matte color: grey74
  Background color: white
  Border color: srgb(223,223,223)
  Transparent color: none
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 4160x3120+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: JPEG
  Quality: 98
  Orientation: RightTop
  Properties:
    date:create: 2019-05-01T16:09:43+00:00
    date:modify: 2019-05-01T16:09:43+00:00
    exif:ApertureValue: 200/100
    exif:BrightnessValue: 0/100
    exif:ColorSpace: 1
    exif:ComponentsConfiguration: 1, 2, 3, 0
    exif:DateTime: 2019:05:01 10:15:04
    exif:DateTimeDigitized: 2019:05:01 10:15:04
    exif:DateTimeOriginal: 2019:05:01 10:15:04
    exif:ExifOffset: 285
    exif:ExifVersion: 48, 50, 50, 48
    exif:ExposureBiasValue: 0/6
    exif:ExposureMode: 0
    exif:ExposureProgram: 0
    exif:ExposureTime: 9994945/1000000000
    exif:Flash: 0
    exif:FlashPixVersion: 48, 49, 48, 48
    exif:FNumber: 200/100
    exif:FocalLength: 3580/1000
    exif:FocalLengthIn35mmFilm: 0
    exif:GPSInfo: 831
    exif:ImageLength: 3120
    exif:ImageWidth: 4160
    exif:InteroperabilityOffset: 801
    exif:Make: HMD Global
    exif:MakerNote: 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 37, 0, 0, 208, 7, 33, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 2, 104, 1, 0, 0, 0, 0
    exif:MeteringMode: 0
    exif:Model: Nokia 8
    exif:Orientation: 6
    exif:PhotographicSensitivity: 100
    exif:PixelXDimension: 4160
    exif:PixelYDimension: 3120
    exif:ResolutionUnit: 2
    exif:SceneCaptureType: 0
    exif:SceneType: 0
    exif:SensingMethod: 0
    exif:ShutterSpeedValue: 6644/1000
    exif:Software: TA-1004_00WW-user 9 PPR1.180610.011 00WW_5_14A release-keys
    exif:SubSecTime: 733
    exif:SubSecTimeDigitized: 733
    exif:SubSecTimeOriginal: 733
    exif:thumbnail:Compression: 6
    exif:thumbnail:InteroperabilityIndex: R98
    exif:thumbnail:InteroperabilityVersion: 48, 49, 48, 48
    exif:thumbnail:JPEGInterchangeFormat: 943
    exif:thumbnail:JPEGInterchangeFormatLength: 6845
    exif:thumbnail:Orientation: 6
    exif:thumbnail:ResolutionUnit: 2
    exif:thumbnail:XResolution: 72/1
    exif:thumbnail:YResolution: 72/1
    exif:WhiteBalance: 0
    exif:XResolution: 72/1
    exif:YCbCrPositioning: 1
    exif:YResolution: 72/1
    jpeg:colorspace: 2
    jpeg:sampling-factor: 2x2,1x1,1x1
    signature: d450d8dbb135c549364b3663c8195164a73698999b8104e75c8b74564835986f
  Profiles:
    Profile-exif: 7794 bytes
  Artifacts:
    verbose: true
  Tainted: False
  Filesize: 6.05972MiB
  Number pixels: 12979200
  Pixels per second: 82.8219MP
  User time: 0.150u
  Elapsed time: 0:01.156
  Version: ImageMagick 7.0.8-42 Q16 x86_64 2019-04-24 https://imagemagick.org

修改后的图片
$ exiftool -Orientation output.jpg 

完整输出:

$ identify -verbose output.jpg 
Image: output.jpg
  Format: JPEG (Joint Photographic Experts Group JFIF format)
  Mime type: image/jpeg
  Class: DirectClass
  Geometry: 1800x1350+0+0
  Units: Undefined
  Colorspace: sRGB
  Type: TrueColor
  Base type: Undefined
  Endianess: Undefined
  Depth: 8-bit
  Channel depth:
    Red: 8-bit
    Green: 8-bit
    Blue: 8-bit
  Channel statistics:
    Pixels: 2430000
    Red:
      min: 0  (0)
      max: 255 (1)
      mean: 108.075 (0.423823)
      standard deviation: 60.7286 (0.238152)
      kurtosis: -0.889179
      skewness: -0.260768
      entropy: 0.940096
    Green:
      min: 0  (0)
      max: 255 (1)
      mean: 105.629 (0.414232)
      standard deviation: 59.6505 (0.233924)
      kurtosis: -0.993155
      skewness: -0.0409431
      entropy: 0.957277
    Blue:
      min: 0  (0)
      max: 255 (1)
      mean: 93.7942 (0.367821)
      standard deviation: 63.0086 (0.247093)
      kurtosis: -1.00904
      skewness: 0.322794
      entropy: 0.957105
  Image statistics:
    Overall:
      min: 0  (0)
      max: 255 (1)
      mean: 102.499 (0.401958)
      standard deviation: 61.1293 (0.239723)
      kurtosis: -1.03828
      skewness: 0.00662106
      entropy: 0.951493
  Rendering intent: Perceptual
  Gamma: 0.454545
  Chromaticity:
    red primary: (0.64,0.33)
    green primary: (0.3,0.6)
    blue primary: (0.15,0.06)
    white point: (0.3127,0.329)
  Matte color: grey74
  Background color: white
  Border color: srgb(223,223,223)
  Transparent color: none
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 1800x1350+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: JPEG
  Quality: 72
  Orientation: Undefined
  Properties:
    comment: Lavc58.35.100
    date:create: 2019-05-01T16:09:44+00:00
    date:modify: 2019-05-01T16:09:44+00:00
    jpeg:colorspace: 2
    jpeg:sampling-factor: 2x2,1x1,1x1
    signature: 76f0debf16f9a958b603a08a706b825e4700093b28b57470a34361b396da612d
  Artifacts:
    verbose: true
  Tainted: False
  Filesize: 105397B
  Number pixels: 2430000
  Pixels per second: 117.945MP
  User time: 0.020u
  Elapsed time: 0:01.020
  Version: ImageMagick 7.0.8-42 Q16 x86_64 2019-04-24 https://imagemagick.org

解决方案

为了解决这个问题,我在我的bash脚本中加入了一些代码来读取原始文件($file)的方向。然后我更新了输出文件($outfile)的方向。

# read orientation from original image
orientation=$(exiftool -Orientation -n -S $file | grep -Eo '[0-9]{1,4}')

# scale image
ffmpeg -i $file -vf "scale='min($ffmpeg_maxwidth,iw)':-1" $outfile

# set orientation value for the new image
exiftool -n -Orientation=$orientation $outfile

这个有效。谢谢。 - iphonic

4
这里可能的情况是,你的文件都以横向格式存储,但其中一些具有指示应旋转显示的EXIF标签。(许多相机会根据相机的方向自动生成这些标签。)ffmpeg不识别这些标签,因此图像会按照文件中存储的方式读取。ffmpeg主要是一个视频转换工具,而不是图像转换工具,所以我认为它没有任何方法来读取EXIF标签。然而,ImageMagick的convert工具可以做到; 您可以使用-auto-orient标志来启用此功能

这个非常棒的答案在我进行了30分钟“十字军东征”之后拯救了我。谢谢。 - thvs86
自动方向部分是基础的,谢谢! https://imagemagick.org/script/command-line-options.php#auto-orient - Haine

2

@Jaketr00,我知道你可能已经晚了找到这个答案,但我希望它能帮助其他遇到同样问题的人。 要避免这个问题,你需要使用“转置”功能。 假设你想在肖像图像中间画一条红色的水平线。以下命令可以完成任务而不会产生意外旋转。输出将具有与输入文件相同的比例。

ffmpeg -i test.jpg -filter_complex "[0]transpose=1[tr]; color=red:s=300x500,geq=lum='p(X,Y)':a='if(eq(250,Y),255,0)'[c]; [tr][c]overlay=0:0:shortest=1" test_out.jpg`

同样的方法也适用于其他过滤器。你只需要根据自己选择的过滤器来调整这个命令即可。

2
这个可以工作,但是会旋转所有的图片,包括那些本来就正确的。 - gugateider
哇,谢谢您的答案,它对我非常有效! - Rohan Arora

1
尝试在您的ffmpeg命令行中添加选项-noautorotate
此外,请使用exiftool备份exif信息,并在应用ffmpeg缩放后还原备份的exif信息。
for f in *.jpg
do 
    # save exif information
    ffmpeg -noautorotate -i input.jpg -vf "scale=w:h" output.jpg
    # retore exif information
done

3
它仍在旋转。 - ZomoXYZ
@Jaketr00 或许有一些 exif 标签被 ffmpeg 忽略了。在使用 ffmpeg 进行缩放之前,使用 exiftool 获取 exif 信息并保存,然后应用 ffmpeg 进行缩放,最后将保存的 exif 信息设置到你的缩放图像中。 - alijandro
但是我不想对我 676 张图片中的每一张都这样做。 - ZomoXYZ

0

我在尝试从照片制作缩略图时遇到了类似的问题,它们的方向不正确。
所以我发现ffmpeg transpose 对我来说完美地解决了这个问题。
但是我不知道它在性能方面是否最优。
我的做法:

   std::string transpose = buildTransposeCommand(exif);
   sprintf((char *) commandBuf,
        "%s -i \"%s\" -vf \"scale=320:-1:sws_flags=sinc, %s\" \"%s\" -y\n",
        FFMPEG_PATH,
        in_path_.c_str(),
        transpose.c_str(),
        out_path_.c_str()
   );

    std::string Thumbnail::buildTransposeCommand(int & exif) {
        std::string transpose;
        if (exif == 6) transpose = "transpose=clock";
        else if (exif == 8) transpose = "transpose=cclock";
        else if (exif == 3) transpose = "transpose=clock,transpose=clock";
        else if (exif == 2) transpose = "transpose=clock_flip,transpose=cclock";
        else if (exif == 5) transpose = "transpose=cclock_flip";
        else if (exif == 7) transpose = "transpose=cclock_flip,transpose=clock,transpose=clock";
        else if (exif == 4) transpose = "transpose=clock_flip,transpose=clock";
        return transpose;
    }

我强烈推荐使用https://github.com/ianare/exif-samples这些样本进行测试,它对我帮助很大。
看一下方向文件夹。


0

FFmpeg 似乎不是完成这项工作的正确工具。除非在最后,如果您想将 .jpg 图像组装成视频,则可以使用它。

如果您使用 FFmpeg 来制作带有图像的视频,则无需先调整其大小。 FFmpeg 可以将它们缩放到所需的视频尺寸。

要根据其 Exif 方向标签旋转图像并进行无损处理,例如,您可以使用 exiftran

exiftran -a -i -b *.jpg

使用的标志的含义:

-a     Automatic (using exif orientation tag).
-i     Enable in-place editing of the images.
-b     Create a backup file when doing in-place editing 

之后,您可以使用ffmpeg将它们组合成一个视频。例如:

ffmpeg -framerate 1/3 -pattern_type glob -i '*.jpg' \
 -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2,setsar=1" \
 -c:v libx264 -crf 20 -r 25 -pix_fmt yuv420p \
 OUTPUT.MP4

如果您需要具有正确方向的调整大小的JPEG图像,可以使用ImageMagick的。例如:
mogrify -path /path/to/new_images \
 -auto-orient -resize "1920x1080>" \
 -background black -gravity center -extent 1920x1080 *.jpg

在调整大小的尺寸末尾的>表示仅调整较大的图像,而不是较小的图像。


-1

您需要在系统目录上运行所有现有的图像。因为ffmpeg没有可用选项来消除保持方向所需的exiftool。

我不想仅仅为了这个问题安装和包含ImageMagick。因为我已经在使用ffmpeg进行视频转换。

在ffmpeg命令中添加-noautorotate没有任何效果。因此,这里是@alijandro答案的更详细版本,使用来自here的示例代码的nodejs脚本来保留方向的元数据。同时,这也适用于您的样例图像。

const ffmpeg = require("ffmpeg");
const exiftool = require("node-exiftool");
const exiftoolBin = require("dist-exiftool");
const sizeOf = require("image-size");

const ep = new exiftool.ExiftoolProcess(exiftoolBin);
let metaData = {};
ep.open()
  .then(() => ep.readMetadata('input-img.jpeg', ["-File:all"]))
  .then((data) => {
    console.log("meta read");
    metaData = data;
  }, console.error)
  .then((data) => {
    const d = sizeOf('input-img.jpeg');
    const sizeFactor = d.height > d.width ? `-1:${maxH}` : `${maxW}:-1`;
    exec(
     `ffmpeg -noautorotate -i input-img.jpeg -vf scale="${sizeFactor}" -y output-img.jpeg`, 
      (err) => {
        // handle error
        console.log("resized");
        ep.open()
          .then((data) => {
            console.log("meta write");
            ep.writeMetadata('output-img.jpeg', metaData.data[0], ["overwrite_original"]);
          }, console.error)
          .then(() => ep.close())
          .catch(console.error);
      }
    );
  }, console.error)
  .then(() => ep.close())
  .catch(console.error);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接