吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3479|回复: 122
上一主题 下一主题
收起左侧

[原创工具] 03-18更新,增加可调参数,增加多线程处理_图片黑白二值化的小工具,300多k,文件...

  [复制链接]
跳转到指定楼层
楼主
858983646 发表于 2025-3-12 21:24 回帖奖励
本帖最后由 858983646 于 2025-3-18 19:16 编辑

不需要麻烦操作,拖过来就好,支持单个多个图片和单个文件夹简单图片漂白,免得打印出来一团黑,适合要求不高的场景,主要就是方便
速度很快,i5-6500测试了下1080p的图片,800张70多秒

03-18更新,增加了文件夹处理时多文件多线程处理,比原来快多了。单文件拖拽还是单图片拆分了多线程
参数也可以修改设置了,保存固定为了png格式,颜色索引模式,体积也小了好几倍

图片黑白二值化8.0(双击看说明)-11-0.05.zip

289.22 KB, 下载次数: 30, 下载积分: 吾爱币 -2 CB

可以修改参数了,加了文件夹转换多线程处理,速度快多了

免费评分

参与人数 25吾爱币 +29 热心值 +24 收起 理由
ithanyun + 1 + 1 谢谢@Thanks!
墨与非 + 1 + 1 谢谢@Thanks!
mikezhql + 1 + 1 谢谢@Thanks!
viconly + 1 谢谢@Thanks!
RedGown + 1 谢谢@Thanks!
HAPPYCHICK + 1 + 1 谢谢@Thanks!
Ali2580 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
fm365 + 1 + 1 谢谢@Thanks!
风之暇想 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Yunsu + 1 + 1 win11可以用吗?
LakeBlue + 1 + 1 谢谢@Thanks!
lflxp + 1 + 1 谢谢@Thanks!
yanglinman + 1 + 1 谢谢@Thanks!
wangxp + 1 + 1 谢谢@Thanks!
lkwcz + 1 + 1 鼓励转贴优秀软件安全工具和文档!
daidai0516 + 1 我很赞同!
lsc987 + 1 + 1 我很赞同!
抱薪风雪雾 + 1 + 1 谢谢@Thanks!
rufengyj + 1 + 1 谢谢@Thanks!
yusen7983 + 1 + 1 谢谢@Thanks!
ehu4ever + 1 + 1 谢谢@Thanks!
shroer + 1 + 1 谢谢@Thanks!
schtg + 1 + 1 谢谢@Thanks!
柒點 + 1 + 1 谢谢@Thanks!
helh0275 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
 楼主| 858983646 发表于 2025-3-12 21:59 |楼主
源码有需要的可以自己改改
[C] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <pthread.h>
#include <dirent.h> // 用于遍历文件夹
#include <sys/stat.h> // 用于检查文件是否存在
 
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
 
// 添加平台相关的头文件
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
 
typedef struct {
    int width;
    int height;
    unsigned char *data;
} GrayscaleImage;
 
typedef struct {
    double *integral;
    double *integral_sq;
    int w;
    int h;
} IntegralData;
 
IntegralData* create_integral(GrayscaleImage *img) {
    IntegralData *id = malloc(sizeof(IntegralData));
    id->w = img->width;
    id->h = img->height;
     
    id->integral = calloc(id->w * id->h, sizeof(double));
    id->integral_sq = calloc(id->w * id->h, sizeof(double));
 
    double row_sum = 0, row_sum_sq = 0;
    for(int x=0; x<id->w; x++){
        double val = img->data[x];
        row_sum += val;
        row_sum_sq += val*val;
        id->integral[x] = (x>0) ? id->integral[x-1] + val : val;
        id->integral_sq[x] = (x>0) ? id->integral_sq[x-1] + val*val : val*val;
    }
 
    for(int y=1; y<id->h; y++){
        row_sum = 0;
        row_sum_sq = 0;
        for(int x=0; x<id->w; x++){
            int idx = y*id->w + x;
            double val = img->data[idx];
            row_sum += val;
            row_sum_sq += val*val;
             
            double up = id->integral[(y-1)*id->w + x];
            id->integral[idx] = up + row_sum;
            id->integral_sq[idx] = id->integral_sq[(y-1)*id->w + x] + row_sum_sq;
        }
    }
    return id;
}
 
void get_local_stats(IntegralData *id, int x, int y, int radius,
                    double *mean, double *stddev)
{
    int x1 = fmax(0, x - radius);
    int y1 = fmax(0, y - radius);
    int x2 = fmin(id->w-1, x + radius);
    int y2 = fmin(id->h-1, y + radius);
     
    int area = (x2-x1+1)*(y2-y1+1);
    if(area == 0) {
        *mean = 0;
        *stddev = 0;
        return;
    }
 
    double sum = id->integral[y2*id->w + x2];
    if(x1 > 0) sum -= id->integral[y2*id->w + x1-1];
    if(y1 > 0) sum -= id->integral[(y1-1)*id->w + x2];
    if(x1>0 && y1>0) sum += id->integral[(y1-1)*id->w + x1-1];
 
    double sum_sq = id->integral_sq[y2*id->w + x2];
    if(x1 > 0) sum_sq -= id->integral_sq[y2*id->w + x1-1];
    if(y1 > 0) sum_sq -= id->integral_sq[(y1-1)*id->w + x2];
    if(x1>0 && y1>0) sum_sq += id->integral_sq[(y1-1)*id->w + x1-1];
 
    *mean = sum / area;
    double variance = (sum_sq / area) - (*mean * *mean);
    *stddev = sqrt(fmax(variance, 0.0));
}
 
typedef struct {
    GrayscaleImage *img;
    IntegralData *id;
    int start_row;
    int end_row;
    int radius;
    double k;
    double R;
} ThreadArgs;
 
void* thread_function(void* args) {
    ThreadArgs *targs = (ThreadArgs*)args;
    GrayscaleImage *img = targs->img;
    IntegralData *id = targs->id;
    int radius = targs->radius;
    double k = targs->k;
    double R = targs->R;
 
    for(int y = targs->start_row; y < targs->end_row; y++) {
        for(int x = 0; x < img->width; x++) {
            double mean, stddev;
            get_local_stats(id, x, y, radius, &mean, &stddev);
            double threshold = mean * (1.0 + k * (stddev/R - 1.0));
            img->data[y*img->width + x] = (img->data[y*img->width + x] > threshold) ? 255 : 0;
        }
    }
    return NULL;
}
 
 
 
void sauvola_binarize(GrayscaleImage *img, int window_size, double k) {
    int radius = window_size / 2;
    IntegralData *id = create_integral(img);
     
    double R = 0;
    for(int i=0; i<img->width*img->height; i++)
        if(img->data[i] > R) R = img->data[i];
    R = fmax(R, 1.0);
 
    // 自动获取CPU核心数
    int num_threads = 4;  // 默认值
#ifdef _WIN32
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    num_threads = sysInfo.dwNumberOfProcessors;
#else
    long nproc = sysconf(_SC_NPROCESSORS_ONLN);
    if (nproc > 0) {
        num_threads = (int)nproc;
    }
#endif
    // 确保至少1个线程
    num_threads = num_threads > 0 ? num_threads : 1;
 
    pthread_t *threads = malloc(num_threads * sizeof(pthread_t));
    ThreadArgs *args = malloc(num_threads * sizeof(ThreadArgs));
 
    int rows_per_thread = (img->height + num_threads - 1) / num_threads;
 
    for(int i = 0; i < num_threads; i++) {
        args[i].img = img;
        args[i].id = id;
        args[i].radius = radius;
        args[i].k = k;
        args[i].R = R;
        args[i].start_row = i * rows_per_thread;
        args[i].end_row = fmin((i + 1) * rows_per_thread, img->height);
        pthread_create(&threads[i], NULL, thread_function, &args[i]);
    }
 
    for(int i = 0; i < num_threads; i++) {
        pthread_join(threads[i], NULL);
    }
 
    free(threads);
    free(args);
    free(id->integral);
    free(id->integral_sq);
    free(id);
}
 
 
// 检查文件是否是图片
int is_image_file(const char *filename) {
    const char *ext = strrchr(filename, '.');
    if (!ext) return 0;
    if (strcmp(ext, ".png") == 0 || strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0 || strcmp(ext, ".bmp") == 0) {
        return 1;
    }
    return 0;
}
 
// 处理单个图片文件
void process_image_file(const char *input_path) {
    int w, h, ch;
    unsigned char *data = stbi_load(input_path, &w, &h, &ch, 1);
    if (!data) {
        fprintf(stderr, "无法加载图片: %s\n", input_path);
        return;
    }
 
    GrayscaleImage img = {w, h, data};
    sauvola_binarize(&img, 11, 0.05);
 
    // 构造输出文件名
    char output_path[256];
    const char *dot = strrchr(input_path, '.');
    if (dot) {
        snprintf(output_path, sizeof(output_path), "%.*s_sauvola%s", (int)(dot - input_path), input_path, dot);
    } else {
        snprintf(output_path, sizeof(output_path), "%s_sauvola", input_path);
    }
 
    stbi_write_png(output_path, w, h, 1, img.data, w);
    stbi_image_free(data);
    printf("处理完成: %s -> %s\n", input_path, output_path);
}
 
// 处理文件夹
void process_folder(const char *folder_path) {
    DIR *dir = opendir(folder_path);
    if (!dir) {
        fprintf(stderr, "无法打开文件夹: %s\n", folder_path);
        return;
    }
 
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        // 检查是否是文件
        char file_path[256];
        snprintf(file_path, sizeof(file_path), "%s/%s", folder_path, entry->d_name);
 
        struct stat path_stat;
        if (stat(file_path, &path_stat) == 0) {
            if (S_ISREG(path_stat.st_mode)) { // 检查是否是普通文件
                if (is_image_file(entry->d_name)) {
                    process_image_file(file_path);
                }
            }
        }
    }
    closedir(dir);
}
 
int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("用法: 将图片或文件夹拖放到此exe上\n");
        return 1;
    }
 
    for (int i = 1; i < argc; i++) {
        const char *path = argv[i];
 
        // 检查是否是文件夹
        struct stat path_stat;
        if (stat(path, &path_stat) == 0) {
            if (S_ISDIR(path_stat.st_mode)) {
                process_folder(path);
            } else {
                process_image_file(path);
            }
        } else {
            fprintf(stderr, "无效的路径: %s\n", path);
        }
    }
 
    return 0;
}
推荐
 楼主| 858983646 发表于 2025-3-12 22:19 |楼主
推荐
 楼主| 858983646 发表于 2025-3-12 21:58 |楼主
caochunyuan 发表于 2025-3-12 21:30
试了一下,2MB的图片,会变成1MB的,总的来说还算可以,就是背景还有一些黑点。

参数不调整只能这样了,没办法,手动设置参数又太麻烦了没必要用这个东西
推荐
schtg 发表于 2025-3-13 06:52
下载了,在win10下试用,没有反应呢。
推荐
 楼主| 858983646 发表于 2025-3-12 22:07 |楼主

虚拟机测试 win7 x86 sp1可以的,但是我之前单位老电脑win7确实不行,我也不知道什么原因
推荐
 楼主| 858983646 发表于 2025-3-12 22:51 |楼主
Elaineliu 发表于 2025-3-12 22:47
为什么不用PM Lite呢,漂白软件有专门算法

那个我也下了,主要上班要求不高,不是打印出来很糊一坨就可以,这样更方便
推荐
 楼主| 858983646 发表于 2025-3-13 08:40 |楼主
yangliu9420 发表于 2025-3-13 08:02
请教一下,黑白“二值化”是什么意思?

颜色变成纯黑和纯白两种啊
推荐
 楼主| 858983646 发表于 2025-3-13 08:46 |楼主

颜色大于某个值就纯黑,否则纯白
推荐
 楼主| 858983646 发表于 2025-3-13 09:32 |楼主
znw16899 发表于 2025-3-13 09:27
win10双击无法运行,是我方法不对吗

把图片或者文件夹拖到这个exe上,双击本来就不行
7#
caochunyuan 发表于 2025-3-12 21:30
试了一下,2MB的图片,会变成1MB的,总的来说还算可以,就是背景还有一些黑点。
8#
BG8HVH 发表于 2025-3-12 22:02
win7不能运行
9#
蓝箭 发表于 2025-3-12 22:10
运行了没反应。
10#
Elaineliu 发表于 2025-3-12 22:47
为什么不用PM Lite呢,漂白软件有专门算法

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
sunmoon007 + 1 + 1 我很赞同!

查看全部评分

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-3-20 03:34

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表