- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试使用从摄像机获取的 jpeg 制作 gif 动画。但是这个过程是虚幻的漫长。我使用了两个不同的库。 First是用 native C++ 代码编写的,其次是 Java 的 one .
我尽可能地压缩帧,但即使这样也不能减少生成时间。
native 库需要大约 80-100 秒,Java 需要大约 40-60 秒(我不知道 java 是如何快 2 倍,但日志显示这个结果)5 秒视频 16 fps(每 80 帧)动图)。
我根据this修改了一点C++算法,因为我遇到了同样的问题(通过更改一段代码和更改整个 learn()
函数尝试了两个版本)。
在这里你可以看到一段日志:
它是 native 实现中的最后三帧:
D/TimeUtils: Adding frame executed in 949ms
D/TimeUtils: Adding frame executed in 976ms
D/TimeUtils: Adding frame executed in 1028ms
D/TimeUtils: Creating gif with native library executed in 82553ms
这是 Java 版本的最后三帧:
D/TimeUtils: Adding frame executed in 541ms
D/TimeUtils: Adding frame executed in 513ms
D/TimeUtils: Adding frame executed in 521ms
D/TimeUtils: Creating gif with nbadal's library executed in 44811ms
也许还有一些其他有用的日志:
D/CameraActivity: Duration of the captured video is 5000ms
V/CameraActivity: Dimensions are 288w x 288h
D/CameraActivity: Final bitmaps count: 80
TimeUtils.java 包含检查方法执行时间的静态方法。
NativeGifConverter.java(仅转换函数):
@Override public void createGifFile(String path, List<String> bitmapPaths) {
Bitmap bitmap = BitmapUtils.retrieve(bitmapPaths.get(0));
if (init(path, bitmap.getWidth(), bitmap.getHeight(), mNumColors, mQuality, mFrameDelay) != 0) {
Timber.e("Gifflen init failed");
return;
}
bitmap.recycle();
for (String bitmapPath : bitmapPaths) {
bitmap = howLong("Retrieving bitmap", () -> BitmapUtils.retrieve(bitmapPath));
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
final int[] pixels = new int[width * height];
final Bitmap finalBitmap = bitmap; // for counting time
howLongVoid("Retrieving pixels", () -> finalBitmap.getPixels(pixels, 0, width, 0, 0, width, height));
howLongVoid("Adding frame", () -> addFrame(pixels));
bitmap.recycle();
}
bitmap = null;
close();
}
NbadalGifConverter.java(仅转换函数):
@Override public void createGifFile(String path, List<String> bitmapsNames) {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final AnimatedGifEncoder encoder = new AnimatedGifEncoder();
encoder.setDelay(mDelay);
encoder.setQuality(mQuality);
encoder.start(bos);
for (String bitmapName : bitmapsNames) {
final Bitmap bitmap = howLong("Retrieving bitmap", () -> BitmapUtils.retrieve(bitmapName));
howLongVoid("Adding frame", () -> encoder.addFrame(bitmap));
}
encoder.finish();
FileUtils.store(bos.toByteArray(), path.substring(0, path.lastIndexOf('.')) + ".gif");
}
我愿意向您展示另一段相关代码。如果有任何帮助,我将不胜感激。
[更新]
检索位图的日志:
D/TimeUtils: Retrieving bitmap executed in 3ms
D/TimeUtils: Retrieving bitmap executed in 3ms
D/TimeUtils: Retrieving bitmap executed in 4ms
最佳答案
首先我要感谢@Spektre 的回答:Effective gif/image color quantization?
我和我的同事刚刚将它从 C++ 翻译成 Java。它在 4 倍的时间内显示出良好的结果。我会尝试改进它,但这已经比 AnimatedGifEncoder.java(我以前用过)好得多
代码如下:
public static final int MAX_COLOR_COUNT = 65536;
/**
* @param pixels rgb 888
* @param palette int[256]
* @return indices of colors in palette
*/
private int[][][] createPalette(int[] pixels, int[] palette) {
final int[] histogram = new int[MAX_COLOR_COUNT]; // pixel count histogram
final int[] indices = new int[MAX_COLOR_COUNT]; // here index is color value
for (int i = 0; i < MAX_COLOR_COUNT; i++) {
indices[i] = i;
}
// creating histogram
for (int color : pixels) {
// 0001 1111 0111 1110 0000 1111 1000 0000 0000
color = ((color >> 3) & 0x1F) | ((color >> 5) & 0x7E0) | ((color >> 8) & 0xF800);
if (histogram[color] < Integer.MAX_VALUE) { // picture must be really big
histogram[color]++;
}
}
// removing zeros
int j = 0;
for (int i = 0; i < MAX_COLOR_COUNT; i++) {
histogram[j] = histogram[i];
indices[j] = indices[i];
if (histogram[j] != 0) {
j++;
}
}
final int histograms = j;
// bubble sort
for (int i = 1; i != 0; ) {
i = 0;
for (int x = 0, y = 1; y < histograms; x++, y++) {
if (histogram[x] < histogram[y]) {
i = histogram[x];
histogram[x] = histogram[y];
histogram[y] = i;
i = indices[x];
indices[x] = indices[y];
indices[y] = i;
i = 1;
}
}
}
final int[][][] colorMap = new int[32][64][32];
int colorTableIndex = 0, x = 0;
for (; x < histograms; x++) { // main colors
final int color = indices[x];
// 1f (16) = 0001 1111 (2)
// 3f (16) = 0011 1111 (2)
// (1111 1)(111 111)(1 1111)
final int b = color & 0x1f;
final int g = (color >> 5) & 0x3f;
final int r = (color >> 11) & 0x1f;
// skip if similar color already in palette[]
int a = 0, i = 0;
for (; i < colorTableIndex; i++) {
final byte tempB = (byte) ((palette[i] >> 3) & 0x1f);
final byte tempG = (byte) ((palette[i] >> 10) & 0x3f);
final byte tempR = (byte) ((palette[i] >> 19) & 0x1f);
// if difference between two colors is pretty small
// taxicab distance
int difference = tempB - b;
if (difference < 0) {
difference = -difference;
}
a = difference;
difference = tempG - g;
if (difference < 0) {
difference = -difference;
}
a += difference;
difference = tempR - r;
if (difference < 0) {
difference = -difference;
}
a += difference;
if (a <= 2) { // smaller than 16/8
a = 1;
break;
}
a = 0;
}
if (a != 0) {
colorMap[r][g][b] = i; // map to existing color
} else {
colorMap[r][g][b] = colorTableIndex; // map to new index
// 1111 1000 1111 1100 1111 1000
palette[colorTableIndex] = b << 3 | (g << 10) | (r << 19); // fill this index with new color
colorTableIndex++;
if (colorTableIndex >= 256/*palette.length*/) {
x++;
break;
}
}
} // colorTableIndex = new color table size
for (; x < histograms; x++) { // minor colors
final int color = indices[x];
final int b = color & 0x1f;
final int g = (color >> 5) & 0x3f;
final int r = (color >> 11) & 0x1f;
// find closest color
int minDistance = -1;
int colorIndex = 0;
for (int a, i = 0; i < colorTableIndex; i++) {
final byte tempB = (byte) ((palette[i] >> 3) & 0x1f);
final byte tempG = (byte) ((palette[i] >> 10) & 0x3f);
final byte tempR = (byte) ((palette[i] >> 19) & 0x1f);
int difference = tempB - b;
if (difference < 0) {
difference = -difference;
}
a = difference;
difference = tempG - g;
if (difference < 0) {
difference = -difference;
}
a += difference;
difference = tempR - r;
if (difference < 0) {
difference = -difference;
}
a += difference;
if ((minDistance < 0) || (minDistance > a)) {
minDistance = a;
colorIndex = i;
}
}
colorMap[r][g][b] = colorIndex;
}
return colorMap;
}
private byte[] map(int[] pixels, int[][][] colorMap) {
final int pixelsLength = pixels.length;
final byte[] mapped = new byte[pixelsLength];
for (int i = 0; i < pixelsLength; i++) {
final int color =
((pixels[i] >> 3) & 0x1F) | ((pixels[i] >> 5) & 0x7E0) | ((pixels[i] >> 8) & 0xF800);
final int b = color & 0x1f;
final int g = (color >> 5) & 0x3f;
final int r = (color >> 11) & 0x1f;
mapped[i] = (byte) colorMap[r][g][b];
}
return mapped;
}
关于java - 将 jpeg 转换为 gif 太长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33941767/
在 Google 和许多 DICOM 章节中可以轻松找到有关 JPEG-LS 的信息。 但是,也有提到 JPEG-LL 的链接/页面/阅读资料。但是,我更深入地研究了 DICOM 标准,没有一章提到过
我有一个关于 DICOM 标准和 libjpeg 库的问题。在 DICOM 标准中,除其他外,还有传输语法: JPEG Lossless, Nonhierarchical, First- Order
APP0 到 APP15 标记每个只支持 65535 字节(我从 libjpeg.doc 中读到的)。如果要在 jpeg 文件中保存更大的数据 block 怎么办? 最佳答案 没有限制使用多个相同类型
我正在尝试构建一个上传器,它分两步上传渐进式文件: 上传最小字节数以创建缩略图 (0-10%) 上传缩略图的其余字节。 (11%-100%) 我想这样做是为了让缩略图更早可用,而不必上传单独的缩略图。
所以,假设我有一个大版本的图像,它只显示为缩略图。是否可以通过使用渐进式 jpeg 来避免为缩略图创建单独的文件,在达到一定数量的扫描时停止加载,并且仅在用户选择完全打开它时继续加载? 如果是这样,如
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 去年关闭。 Improve this
很难说出这里问的是什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或言辞激烈,无法以目前的形式合理回答。如需帮助澄清此问题以便可以重新打开,visit the help center . 9年前关闭
我想从 jpeg 中提取缩略图,无需任何外部库。我的意思是这并不太困难,因为我需要知道缩略图在文件中的开始位置和结束位置,然后简单地剪切它。我研究了许多文档(即: http://www.media.m
当 decoding entropy encoded DC values in JPEG (或 entropy encoded prediction differences in lossless J
问题是:如何区分两个文件?一个用 JPEG 编码,另一个用 JPEG2000 编码。 我需要特定于格式的文件读/写函数,我无法在不读取的情况下找到文件编码。JPEG 现在工作正常,但 JPEG fun
是否有结束 exif/end-of-xmp/end-of-iptc/start-of-data 标记,我可以用它来获取 jpg/jpeg(和其他图像格式)的数据部分的校验和? 最佳答案 我认为这个问题
不久前我收到一封电子邮件,其中包含图像附件。从那时起,hotmail 似乎已停止为我托管图像,因为当我打开邮件时,图像不再可用。 但是,消息源仍然完好无损,如果我没记错的话,消息源 - 以文本形式 -
我有一个提供高质量 MJPEG 的网络摄像头。 我需要通过网络发送小的、低质量的 JPEG。我的硬件是树莓派(700MHz ARM)。我希望代码使用尽可能少的 CPU 能力,并尽可能少地增加延迟。我可
有一个question with the same title但不幸的是它对我没有帮助。 我正在尝试解析 SOS 标记的数据。我能找到的所有文档都说在标记( 0xFFDA )之后是一个两字节的数字,它
每个人! 我处理来自 IP 摄像机的视频,并编写了基于解压缩视频分析的运动检测算法。但我真的更快。我找到了几篇关于压缩域分析的论文,但没有找到任何实现。 谁能推荐我一些代码? 找到的 Material
我在一个网站上工作,该网站涉及显示来自各种在线零售商的大量产品图片。由于大部分页面权重都在图像中,因此我认为值得研究一下减少文件大小的技术。 图像已经是 JPEG。我知道 PNG 有很多多余的东西,可
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a software
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 6 年前。 Improve this ques
我有一个网络画廊,我在其中显示用户上传的文件大小和分辨率各不相同的图像。目前所有图像都是基线。所以我想知道如果我将它们转换为逐行图像是否真的会产生重大影响。使用渐进式图像的优点和缺点是什么。 最佳答案
我在许多链接和网站上保持头脑,但未能得到答案。我不想问这个,我知道 JPEG 压缩,它只制作压缩图像。甚至 Motion JPEG 也会制作压缩图像 I 帧。我的问题是有什么区别。我正在为需要发送视频
我是一名优秀的程序员,十分优秀!