Skip to content

Commit eac5563

Browse files
committed
feat: support gif animation input/output
1 parent 252cbae commit eac5563

File tree

11 files changed

+386
-151
lines changed

11 files changed

+386
-151
lines changed

README.md

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -48,38 +48,6 @@ models-Real-ESRGAN-AnimeSharp // directory should have a suffix of models-Real-
4848
* This tool can only convert ESRGAN models, not Real-ESRGAN models. If there are Real-ESRGAN models with perfect effect that need to be converted, I can help you convert them manually.
4949

5050

51-
### About Real-ESRGAN
52-
Real-ESRGAN is a Practical Algorithms for General Image Restoration.
53-
54-
> [[Paper](https://arxiv.org/abs/2107.10833)] [[Project Page]](https://github.com/xinntao/Real-ESRGAN) &emsp; [[YouTube Video](https://www.youtube.com/watch?v=fxHWoDSSvSc)] [[Bilibili](https://www.bilibili.com/video/BV1H34y1m7sS/)] &emsp; [[Poster](https://xinntao.github.io/projects/RealESRGAN_src/RealESRGAN_poster.pdf)] [[PPT slides](https://docs.google.com/presentation/d/1QtW6Iy8rm8rGLsJ0Ldti6kP-7Qyzy6XL/edit?usp=sharing&ouid=109799856763657548160&rtpof=true&sd=true)]<br>
55-
> [Xintao Wang](https://xinntao.github.io/), Liangbin Xie, [Chao Dong](https://scholar.google.com.hk/citations?user=OSDCB0UAAAAJ), [Ying Shan](https://scholar.google.com/citations?user=4oXBp9UAAAAJ&hl=en) <br>
56-
> Tencent ARC Lab; Shenzhen Institutes of Advanced Technology, Chinese Academy of Sciences
57-
58-
![img](https://github.com/xinntao/Real-ESRGAN/raw/master/assets/teaser.jpg)
59-
**Note that RealESRGAN may still fail in some cases as the real-world degradations are really too complex.**
60-
61-
## About RealSR
62-
[[paper]](http://openaccess.thecvf.com/content_CVPRW_2020/papers/w31/Ji_Real-World_Super-Resolution_via_Kernel_Estimation_and_Noise_Injection_CVPRW_2020_paper.pdf) [[project]](https://github.com/jixiaozhong/RealSR) [[NTIRE 2020 Challenge on Real-World Image Super-Resolution: Methods and Results]](https://arxiv.org/pdf/2005.01996.pdf)
63-
64-
## About SRMD
65-
[[paper]](http://openaccess.thecvf.com/content_cvpr_2018/papers/Zhang_Learning_a_Single_CVPR_2018_paper.pdf) [[project]](https://github.com/cszn/SRMD)
66-
![demo](https://github.com/cszn/SRMD/raw/master/figs/realSR1.png)
67-
![demo](https://github.com/cszn/SRMD/raw/master/figs/realSR2.png)
68-
69-
## About Real-CUGAN
70-
[[project]](https://github.com/bilibili/ailab/tree/main/Real-CUGAN)
71-
Real-CUGAN is an AI super resolution model for anime images, trained in a million scale anime dataset, using the same architecture as Waifu2x-CUNet.
72-
73-
## About Anime4kCPP
74-
[[Project]](- https://github.com/TianZerL/Anime4KCPP)
75-
Anime4KCPP provides an optimized [bloc97's Anime4K](https://github.com/bloc97/Anime4K) algorithm version 0.9, and it also provides its own CNN algorithm [ACNet](https://github.com/TianZerL/Anime4KCPP/wiki/ACNet), it provides a variety of way to use, including preprocessing and real-time playback, it aims to be a high performance tools to process both image and video.
76-
This project is for learning and the exploration task of algorithm course in SWJTU.
77-
- Anime4K is a simple high-quality anime upscale algorithm. The version 0.9 does not use any machine learning approaches, and can be very fast in real-time processing or pretreatment.
78-
- ACNet is a CNN based anime upscale algorithm. It aims to provide both high-quality and high-performance.
79-
HDN mode can better denoise, HDN level is from 1 to 3, higher for better denoising but may cause blur and lack of detail.
80-
![demo](https://github.com/TianZerL/Anime4KCPP/raw/master/images/example.png)
81-
82-
8351
## How to build RealSR-NCNN-Android-CLI
8452
### step1
8553
https://github.com/Tencent/ncnn/releases
@@ -241,6 +209,20 @@ RealSR-NCNN-Android-GUI\app\src\main\assets\
241209
up4x-no-denoise.bin
242210
up4x-no-denoise.param
243211
```
212+
## Limitations
213+
This is a very simple tool, flexible and powerful, has the following shortcomings (and there are no plans for improvement):
214+
215+
### About Batch Processing
216+
1. You can load multiple images by opening the album, selecting multiple pictures, sharing, and choosing realsr, but you cannot select multiple images within the app.
217+
2. After loading multiple images, only one image can be previewed; there is no image list.
218+
3. After processing, the results will not be previewed and will be saved directly to the album.
219+
4. Magick (including the quick menu in the top right corner) does not support batch processing.
220+
221+
### About GIF Animation
222+
1. Processing can only be done in GIF animation mode when one GIF is opened; otherwise, only one frame can be processed.
223+
2. GIFs cannot be previewed.
224+
3. After processing is complete, the results will not be previewed and will be saved directly to the album.
225+
4. Magick (including the quick menu in the top right corner) does not support GIF processing.
244226

245227
## Acknowledgement
246228
### original super-resolution projects

README_CHS.md

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -65,34 +65,6 @@ models-Real-ESRGAN-AnimeSharp // 目录需要用 models-Real- 或 models-ESRGAN
6565
├─x4.param
6666
```
6767

68-
## 关于 Real-ESRGAN
69-
Real ESRGAN是一个实用的图像修复算法,可以用来对低分辨率图片完成四倍放大和修复,化腐朽为神奇。
70-
> [[论文](https://arxiv.org/abs/2107.10833)] &emsp; [[项目地址]](https://github.com/xinntao/Real-ESRGAN) &emsp; [[YouTube 视频](https://www.youtube.com/watch?v=fxHWoDSSvSc)] &emsp; [[B站讲解](https://www.bilibili.com/video/BV1H34y1m7sS/)] &emsp; [[Poster](https://xinntao.github.io/projects/RealESRGAN_src/RealESRGAN_poster.pdf)] &emsp; [[PPT slides](https://docs.google.com/presentation/d/1QtW6Iy8rm8rGLsJ0Ldti6kP-7Qyzy6XL/edit?usp=sharing&ouid=109799856763657548160&rtpof=true&sd=true)]<br>
71-
> [Xintao Wang](https://xinntao.github.io/), Liangbin Xie, [Chao Dong](https://scholar.google.com.hk/citations?user=OSDCB0UAAAAJ), [Ying Shan](https://scholar.google.com/citations?user=4oXBp9UAAAAJ&hl=en) <br>
72-
> Tencent ARC Lab; Shenzhen Institutes of Advanced Technology, Chinese Academy of Sciences
73-
74-
![img](https://github.com/xinntao/Real-ESRGAN/raw/master/assets/teaser.jpg)
75-
**现在的 Real-ESRGAN 还是有几率失败的,因为现实中的图片的降质过程比较复杂。**
76-
77-
## 关于 RealSR
78-
[[论文]](http://openaccess.thecvf.com/content_CVPRW_2020/papers/w31/Ji_Real-World_Super-Resolution_via_Kernel_Estimation_and_Noise_Injection_CVPRW_2020_paper.pdf) [[项目地址]](https://github.com/jixiaozhong/RealSR) [[NTIRE 2020 Challenge on Real-World Image Super-Resolution: Methods and Results]](https://arxiv.org/pdf/2005.01996.pdf)
79-
80-
## 关于 SRMD
81-
[[论文]](http://openaccess.thecvf.com/content_cvpr_2018/papers/Zhang_Learning_a_Single_CVPR_2018_paper.pdf) [[项目地址]](https://github.com/cszn/SRMD)
82-
![demo](https://github.com/cszn/SRMD/raw/master/figs/realSR1.png)
83-
![demo](https://github.com/cszn/SRMD/raw/master/figs/realSR2.png)
84-
85-
## 关于 Real-CUGAN
86-
[[项目地址]](https://github.com/bilibili/ailab/tree/main/Real-CUGAN)
87-
Real-CUGAN是一个使用百万级动漫数据进行训练的,结构与Waifu2x兼容的通用动漫图像超分辨率模型。
88-
89-
## 关于 Anime4kCPP
90-
[[项目地址]](- https://github.com/TianZerL/Anime4KCPP)
91-
Anime4KCPP提供一个改进后的[bloc97的Anime4K](https://github.com/bloc97/Anime4K)算法0.9版本,同时也提供自己的CNN算法[ACNet](https://github.com/TianZerL/Anime4KCPP/wiki/ACNet)。Anime4KCPP提供多种使用方式,包括预处理与实时播放,其致力于成为高性能的视频或图像处理工具。
92-
- Anime4K算法是一种简单且高质量的动漫类图像超分辨率算法,它并不使用机器学习,因此速度非常快,可用于实时处理和预处理。
93-
- ACNet是一个基于卷积神经网络的超分辨率算法,旨在同时提供高质量和高性能。其中HDN模式能更好的降噪,HDN等级从1到3,越高降噪效果越好,但可能导致模糊和缺少细节。
94-
![demo](https://github.com/TianZerL/Anime4KCPP/raw/master/images/example.png)
95-
9668
## 如何编译 RealSR-NCNN-Android-CLI
9769
### step1
9870
https://github.com/Tencent/ncnn/releases
@@ -248,6 +220,20 @@ RealSR-NCNN-Android-GUI\app\src\main\assets\
248220
up4x-no-denoise.param
249221
```
250222

223+
## 局限
224+
这是一个非常简易的工具,在灵活和强大的同时,存在如下缺陷(并且没有计划去完善):
225+
### 关于批量处理
226+
1. 可以通过打开相册-选择多个图片-分享-realsr来加载多个图片,不能在应用内选多个图片
227+
2. 加载多个图片后,只能预览1个图片,不会显示图片列表,也无法切换显示不同图片
228+
3. 处理结束后不会预览处理结果,会直接保存到相册
229+
4. Magick(包含右上方快捷菜单)不支持多图处理
230+
231+
### 关于gif动图
232+
1. 仅当打开1张动图时,才能以动图的方式进行处理;否则只能处理1帧
233+
2. 无法预览动图
234+
3. 处理结束后不会预览处理结果,会直接保存到相册
235+
4. Magick(包含右上方快捷菜单)不支持动图处理
236+
251237
## 感谢
252238
### 原始超分辨率项目
253239
- https://github.com/xinntao/Real-ESRGAN

RealSR-NCNN-Android-GUI/app/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ dependencies {
5151
testImplementation 'junit:junit:4.13.2'
5252
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
5353
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
54-
54+
implementation 'com.github.bumptech.glide:glide:4.12.0'
55+
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
5556
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
5657
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package com.tumuyan.ncnn.realsr;
2+
3+
4+
import java.io.BufferedInputStream;
5+
import java.io.File;
6+
import java.io.FileInputStream;
7+
import java.io.IOException;
8+
9+
public class GifUntils {
10+
11+
public static int getGifFrameCount(String filePath) {
12+
try (FileInputStream fis = new FileInputStream(new File(filePath));
13+
BufferedInputStream bis = new BufferedInputStream(fis)) {
14+
// 检查GIF文件头
15+
byte[] header = new byte[6];
16+
if (bis.read(header) != header.length || !isGifHeader(header)) {
17+
return -1;
18+
}
19+
20+
// 读取GIF文件的逻辑屏幕描述符
21+
byte[] lsd = new byte[7];
22+
if (bis.read(lsd) != lsd.length) {
23+
return -1;
24+
}
25+
26+
// 获取帧数
27+
int width = getLowByte(lsd[0]) | (getHighByte(lsd[0]) << 8);
28+
int height = getLowByte(lsd[1]) | (getHighByte(lsd[1]) << 8);
29+
int flags = lsd[3];
30+
boolean hasGlobalColorTable = (flags & 0x80) != 0;
31+
int globalColorTableSize = hasGlobalColorTable ? (int) Math.pow(2, (flags & 0x07) + 1) : 0;
32+
33+
// 跳过全局颜色表
34+
bis.skip(globalColorTableSize * 3);
35+
36+
int frameCount = 0;
37+
while (true) {
38+
int block = bis.read();
39+
if (block == 0x2C) { // 图像数据块
40+
frameCount++;
41+
// 解析图像数据块
42+
byte[] imageDescriptor = new byte[9];
43+
if (bis.read(imageDescriptor) != imageDescriptor.length) {
44+
return frameCount;
45+
}
46+
int localColorTableSize = (imageDescriptor[3] & 0x07) + 1;
47+
bis.skip(localColorTableSize * 3); // 跳过局部颜色表
48+
skipSubBlocks(bis);
49+
} else if (block == 0x21) { // 扩展块
50+
int extensionLabel = bis.read();
51+
if (extensionLabel == 0xF9) { // 图形控制扩展块
52+
bis.skip(4); // 跳过图形控制扩展块
53+
skipSubBlocks(bis);
54+
} else {
55+
skipSubBlocks(bis);
56+
}
57+
} else if (block == 0x3B) { // 文件尾
58+
return frameCount;
59+
} else {
60+
return -1; // 未知块类型
61+
}
62+
}
63+
} catch (IOException e) {
64+
e.printStackTrace();
65+
return -1;
66+
}
67+
}
68+
69+
public static boolean isGifAnimation(String filePath) {
70+
try (FileInputStream fis = new FileInputStream(new File(filePath));
71+
BufferedInputStream bis = new BufferedInputStream(fis)) {
72+
// 检查GIF文件头
73+
byte[] header = new byte[6];
74+
if (bis.read(header) != header.length || !isGifHeader(header)) {
75+
return false;
76+
}
77+
78+
// 读取GIF文件的逻辑屏幕描述符
79+
byte[] lsd = new byte[7];
80+
if (bis.read(lsd) != lsd.length) {
81+
return false;
82+
}
83+
84+
// 获取帧数
85+
int width = getLowByte(lsd[0]) | (getHighByte(lsd[0]) << 8);
86+
int height = getLowByte(lsd[1]) | (getHighByte(lsd[1]) << 8);
87+
int flags = lsd[3];
88+
boolean hasGlobalColorTable = (flags & 0x80) != 0;
89+
int globalColorTableSize = hasGlobalColorTable ? (int) Math.pow(2, (flags & 0x07) + 1) : 0;
90+
91+
// 跳过全局颜色表
92+
bis.skip(globalColorTableSize * 3);
93+
94+
int frameCount = 0;
95+
while (true) {
96+
int block = bis.read();
97+
if (block == 0x2C) { // 图像数据块
98+
frameCount++;
99+
if(frameCount>1)
100+
return true;
101+
// 解析图像数据块
102+
byte[] imageDescriptor = new byte[9];
103+
if (bis.read(imageDescriptor) != imageDescriptor.length) {
104+
return frameCount>1;
105+
}
106+
int localColorTableSize = (imageDescriptor[3] & 0x07) + 1;
107+
bis.skip(localColorTableSize * 3); // 跳过局部颜色表
108+
skipSubBlocks(bis);
109+
} else if (block == 0x21) { // 扩展块
110+
int extensionLabel = bis.read();
111+
if (extensionLabel == 0xF9) { // 图形控制扩展块
112+
bis.skip(4); // 跳过图形控制扩展块
113+
skipSubBlocks(bis);
114+
} else {
115+
skipSubBlocks(bis);
116+
}
117+
} else if (block == 0x3B) { // 文件尾
118+
return frameCount>1;
119+
} else {
120+
return false; // 未知块类型
121+
}
122+
}
123+
} catch (IOException e) {
124+
e.printStackTrace();
125+
return false;
126+
}
127+
}
128+
129+
private static boolean isGifHeader(byte[] header) {
130+
return header[0] == 'G' && header[1] == 'I' && header[2] == 'F';
131+
}
132+
133+
private static int getLowByte(byte b) {
134+
return b & 0xFF;
135+
}
136+
137+
private static int getHighByte(byte b) {
138+
return b & 0xFF;
139+
}
140+
141+
private static void skipSubBlocks(BufferedInputStream bis) throws IOException {
142+
int blockSize;
143+
do {
144+
blockSize = bis.read();
145+
bis.skip(blockSize);
146+
} while (blockSize > 0);
147+
}
148+
}

0 commit comments

Comments
 (0)