图像基本处理算法的简单实现(二)

原文地址链接


4)膨胀腐蚀
         属于什么心态学==,膨胀、腐蚀、击中/击不中变换、细化…(又晕了T^T)。简单点好像就是集合运算,图像与一结构元素的交差补什么的。图像一点的周围是否符合结构元素,然后该怎么处理。
 
         结构元素(B)由0和1组成,用于扫描比较二值化图像(A)。
 
膨胀:
         1、用结构元素B,扫描图像A的每一个像素
         2、用结构元素与其覆盖的二值图像做“与”操作
         3、如果都为0,结果图像的该像素为0。否则为1
 
腐蚀:
         1、用结构元素B,扫描图像A的每一个像素
         2、用结构元素与其覆盖的二值图像做“与”操作
         3、如果都为1,结果图像的该像素为1。否则为0
 
         膨胀腐蚀是形态学处理的基础。(copy的==)
 
膨胀的实现:

<span style="font-family:KaiTi_GB2312;font-size:14px;">/** 
 * 对二值化Bitmap进行膨胀运算后返回 
 * 
 * 膨胀结构元素:3x3 全 
 * 
 * JNIEnv*  jni环境(jni必要参数) 
 * jobject  java对象(jni必要参数) 
 * jintArray    Bitmap所有像素值 
 * int  Bitmap宽度 
 * int  Bitmap高度 
 */ 
JNIEXPORT jintArray JNICALL Java_org_join_image_util_JoinImage_dilation( 
        JNIEnv* env, jobject obj, jintArray buf, int w, int h) { 
    LOGE("==dilation=="); 
 
    jint * cbuf; // 源图像 
    cbuf = (*env)->GetIntArrayElements(env, buf, 0); // 获取int数组元素 
 
    int white = 0xFFFFFFFF; // 不透明白色 
    int black = 0xFF000000; // 不透明黑色 
 
    int size = w * h; 
    jint rbuf[size]; // 目标图像 
    memset(rbuf, black, size * sizeof(jint)); // 将目标图像置成全黑 
 
    int i, j, m, n, gray; 
    jint *p, *q; 
    // 由于使用3×3的结构元素,为防止越界,所以不处理上下左右四边像素 
    for (i = 1; i < h - 1; i++) { 
        for (j = 1; j < w - 1; j++) { 
            p = cbuf + w * i + j; // 指向源图像i行j列 
 
            // 遍历源图像对应结构元素的各点 
            for (m = -1; m <= 1; m++) { 
                for (n = -1; n <= 1; n++) { 
                    gray = (*(p + w * m + n)) & 0xFF; // 获取源图像对应结构元素点的灰度值 
                    // 如果对应3x3范围内有白点(其他色都算为黑) 
                    if (gray == 255) { 
                        q = rbuf + w * i + j; // 指向目标图像i行j列 
                        *q = white; // 将目标图像中的当前点赋成白色 
                        break; 
                    } 
                } 
            } 
        } 
    } 
 
    jintArray result = (*env)->NewIntArray(env, size); // 新建一个jintArray 
    (*env)->SetIntArrayRegion(env, result, 0, size, rbuf); // 将rbuf转存入result 
    (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0); // 释放int数组元素 
    return result; 
} </span>

腐蚀的实现:

/** 
 * 对二值化Bitmap进行腐蚀运算后返回 
 * 
 * 腐蚀结构元素:3x3 全 
 * 
 * JNIEnv*  jni环境(jni必要参数) 
 * jobject  java对象(jni必要参数) 
 * jintArray    Bitmap所有像素值 
 * int  Bitmap宽度 
 * int  Bitmap高度 
 */ 
JNIEXPORT jintArray JNICALL Java_org_join_image_util_JoinImage_erosion( 
        JNIEnv* env, jobject obj, jintArray buf, int w, int h) { 
    LOGE("==erosion=="); 
 
    jint * cbuf; // 源图像 
    cbuf = (*env)->GetIntArrayElements(env, buf, 0); // 获取int数组元素 
 
    int white = 0xFFFFFFFF; // 不透明白色 
    int black = 0xFF000000; // 不透明黑色 
 
    int size = w * h; 
    jint rbuf[size]; // 目标图像 
    memset(rbuf, black, size * sizeof(jint)); // 将目标图像置成全黑 
 
    int i, j, m, n, gray; 
    jint *p, *q; 
    // 由于使用3×3的结构元素,为防止越界,所以不处理上下左右四边像素 
    for (i = 1; i < h - 1; i++) { 
        for (j = 1; j < w - 1; j++) { 
            p = cbuf + w * i + j; // 指向源图像i行j列 
 
            q = rbuf + w * i + j; // 指向目标图像i行j列 
            *q = white; // 将目标图像中的当前点赋成白色 
 
            // 遍历源图像对应结构元素的各点 
            for (m = -1; m <= 1; m++) { 
                for (n = -1; n <= 1; n++) { 
                    gray = (*(p + w * m + n)) & 0xFF; // 获取源图像对应结构元素点的灰度值 
                    // 如果对应3x3范围内有黑点(其他色都算为白) 
                    if (gray == 0) { 
                        *q = black; // 将目标图像中的当前点赋成黑色 
                        break; 
                    } 
                } 
            } 
        } 
    } 
 
    jintArray result = (*env)->NewIntArray(env, size); // 新建一个jintArray 
    (*env)->SetIntArrayRegion(env, result, 0, size, rbuf); // 将rbuf转存入result 
    (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0); // 释放int数组元素 
    return result; 
} 

好吧,都一样的结构元素==,这是偷懒呢。没必要非这样,也可以如“背景色点上下左右>=3点为前景色,则将其填充为前景色”什么的。
 
5)细化
         提取图像骨架的。主要有Zhang快速并行细化方法、Hilditch、Pavlidis、Rosenfeld、索引表细化方法等。
         简述下连通图概念先:分为四连通和八连通(或者称之为邻域)。四连通就是图像上下左右有一点时,才算这两点是连接的;而八连通则周围一圈有一点都行。也就是一点只有右上角有邻点,则是八连通非四连通^^。
         算法按着名字查找下就好==,不想再表述了(实现代码注释了其实有了的^^)。
 
Zhang快速并行细化方法:

<span style="font-family:KaiTi_GB2312;font-size:14px;">/** 
 * 对二值化Bitmap进行细化运算后返回 
 * 
 * 采用“Zhang快速并行细化方法” 
 * 
 * JNIEnv*  jni环境(jni必要参数) 
 * jobject  java对象(jni必要参数) 
 * jintArray    Bitmap所有像素值 
 * int  Bitmap宽度 
 * int  Bitmap高度 
 */ 
JNIEXPORT jintArray JNICALL Java_org_join_image_util_JoinImage_thinning( 
        JNIEnv* env, jobject obj, jintArray buf, int w, int h) { 
    LOGE("==thinning=="); 
 
    jint * cbuf; 
    cbuf = (*env)->GetIntArrayElements(env, buf, 0); // 获取int数组元素 
 
    int black = 0xFF000000; // 不透明黑色 
 
    unsigned char foreground = 0xFF; // 前景灰度值:255(白) 
    unsigned char background = 0; // 背景灰度值:0(黑) 
 
    jboolean modified = 1; // 设置脏标记:true 
    unsigned char count; // 计数器 
    unsigned char mark[w][h]; // 可删除标记 
 
    int size = w * h; // 数据数目 
 
    /* 
     * 8-领域示意图 
     * 
     * P9   P2  P3 
     * P8   P1  P4 
     * P7   P6  P5 
     */ 
 
    int i, j, m, n; // 循环标记 
    unsigned char gray; // 灰度值 
    unsigned char grays[3][3]; // 领域各点灰度值 
    jint *p; // 指向源图像像素的指针 
 
    // 一次迭代操作(直到没有点再满足标记条件) 
    while (modified) { 
        modified = 0; // 设置脏标记:false 
 
        /* 
         * 第一层子循环,删除条件: 
         * 
         * (1.1) 2<=N(p1)<=6 
         * (1.2) S(p1)=1 
         * (1.3) p2*p4*p6=0 
         * (1.4) p4*p6*p8=0 
         * 
         * N(p1):p1的非零邻点的个数 
         * S(p1):以p2 ,p3 ,…… ,p9为序时这些点的值从0到1变化的次数 
         */ 
 
        memset(mark, 0, sizeof(mark)); // 重置删除标记为false 
 
        // 防止越界,不处理上下左右四边像素 
        for (i = 1; i < h - 1; i++) { 
            for (j = 1; j < w - 1; j++) { 
 
                p = cbuf + w * i + j; // 指向源图像i行j列 
                gray = (*p) & 0xFF; // 获得灰度值 
 
                if (gray == foreground) { // 判断是否为细化像素(前景像素) 
 
                    // 计算N(p1) 
                    count = 0; // 重置计数器 
                    for (m = -1; m <= 1; m++) { 
                        for (n = -1; n <= 1; n++) { 
                            gray = (*(p + w * m + n)) & 0xFF; // 获取领域各点的灰度值 
                            grays[m + 1][n + 1] = gray; // 同时存储领域各点的灰度值 
                            if (gray == foreground) { // 如果为前景像素 
                                count++; 
                            } 
                        } 
                    } 
                    count--; // 去除中心点 
 
                    // 判断条件(1.1) 
                    if (2 <= count && count <= 6) { 
                    } else { 
                        continue; // 条件(1.1)不成立,跳出循环 
                    } 
 
                    // 计算S(p1):四周像素由0变255的次数 
                    // 需先计算N(p1),获取领域各点的灰度值 
                    count = 0; // 重置计数器 
                    if (grays[0][1] < grays[0][2]) 
                        count++; // p2->p3 
                    if (grays[0][2] < grays[1][2]) 
                        count++; // p3->p4 
                    if (grays[1][2] < grays[2][2]) 
                        count++; // p4->p5 
                    if (grays[2][2] < grays[2][1]) 
                        count++; // p5->p6 
                    if (grays[2][1] < grays[2][0]) 
                        count++; // p6->p7 
                    if (grays[2][0] < grays[1][0]) 
                        count++; // p7->p8 
                    if (grays[1][0] < grays[0][0]) 
                        count++; // p8->p9 
                    if (grays[0][0] < grays[0][1]) 
                        count++; // p9->p2 
 
                    // 判断条件(1.2) 
                    if (1 == count) { 
                    } else { 
                        continue; // 条件(1.2)不成立,跳出循环 
                    } 
 
                    // 判断条件(1.3) 
                    if (background == grays[0][1] || background == grays[1][2] 
                            || background == grays[2][1]) { 
                    } else { 
                        continue; // 条件(1.3)不成立,跳出循环 
                    } 
 
                    // 判断条件(1.4) 
                    if (background == grays[1][2] || background == grays[2][1] 
                            || background == grays[1][0]) { 
                    } else { 
                        continue; // 条件(1.4)不成立,跳出循环 
                    } 
 
                    /* 
                     * 四条件都成立时 
                     */ 
                    mark[j][i] = 1; // 删除标记为true 
                    modified = 1; // 脏标记为true 
                } 
            } 
        } 
 
        // 由删除标记去除 
        if (modified) { 
            for (i = 1; i < h - 1; i++) { 
                for (j = 1; j < w - 1; j++) { 
                    // 如果删除标记为true 
                    if (1 == mark[j][i]) { 
                        cbuf[w * i + j] = black; // 修改成背景色(黑) 
                    } 
                } 
            } 
        } 
 
        /* 
         * 第二层子循环,删除条件: 
         * 
         * (1.1) 2<=N(p1)<=6 
         * (1.2) S(p1)=1 
         * (2.3) p2*p4*p8=0 
         * (2.4) p2*p6*p8=0 
         */ 
        memset(mark, 0, sizeof(mark)); // 重置删除标记为false 
 
        // 防止越界,不处理上下左右四边像素 
        for (i = 1; i < h - 1; i++) { 
            for (j = 1; j < w - 1; j++) { 
 
                p = cbuf + w * i + j; // 指向源图像i行j列 
                gray = (*p) & 0xFF; // 获得灰度值 
 
                if (gray == foreground) { // 判断是否为细化像素(前景像素) 
 
                    // 计算N(p1) 
                    count = 0; // 重置计数器 
                    for (m = -1; m <= 1; m++) { 
                        for (n = -1; n <= 1; n++) { 
                            gray = (*(p + w * m + n)) & 0xFF; // 获取领域各点的灰度值 
                            grays[m + 1][n + 1] = gray; // 同时存储领域各点的灰度值 
                            if (gray == foreground) { // 如果为前景像素 
                                count++; 
                            } 
                        } 
                    } 
                    count--; // 去除中心点 
 
                    // 判断条件(1.1) 
                    if (2 <= count && count <= 6) { 
                    } else { 
                        continue; // 条件(1.1)不成立,跳出循环 
                    } 
 
                    // 计算S(p1):四周像素由0变255的次数 
                    // 需先计算N(p1),获取领域各点的灰度值 
                    count = 0; // 重置计数器 
                    if (grays[0][1] < grays[0][2]) 
                        count++; // p2->p3 
                    if (grays[0][2] < grays[1][2]) 
                        count++; // p3->p4 
                    if (grays[1][2] < grays[2][2]) 
                        count++; // p4->p5 
                    if (grays[2][2] < grays[2][1]) 
                        count++; // p5->p6 
                    if (grays[2][1] < grays[2][0]) 
                        count++; // p6->p7 
                    if (grays[2][0] < grays[1][0]) 
                        count++; // p7->p8 
                    if (grays[1][0] < grays[0][0]) 
                        count++; // p8->p9 
                    if (grays[0][0] < grays[0][1]) 
                        count++; // p9->p2 
 
                    // 判断条件(1.2) 
                    if (1 == count) { 
                    } else { 
                        continue; // 条件(1.2)不成立,跳出循环 
                    } 
 
                    // 判断条件(2.3) 
                    if (background == grays[0][1] || background == grays[1][2] 
                            || background == grays[1][0]) { 
                    } else { 
                        continue; // 条件(2.3)不成立,跳出循环 
                    } 
 
                    // 判断条件(2.4) 
                    if (background == grays[0][1] || background == grays[2][1] 
                            || background == grays[1][0]) { 
                    } else { 
                        continue; // 条件(2.4)不成立,跳出循环 
                    } 
 
                    /* 
                     * 四条件都成立时 
                     */ 
                    mark[j][i] = 1; // 删除标记为true 
                    modified = 1; // 脏标记为true 
                } 
            } 
        } 
 
        // 由删除标记去除 
        if (modified) { 
            for (i = 1; i < h - 1; i++) { 
                for (j = 1; j < w - 1; j++) { 
                    // 如果删除标记为true 
                    if (1 == mark[j][i]) { 
                        cbuf[w * i + j] = black; // 修改成背景色(黑) 
                    } 
                } 
            } 
        } 
    } 
 
    jintArray result = (*env)->NewIntArray(env, size); // 新建一个jintArray 
    (*env)->SetIntArrayRegion(env, result, 0, size, cbuf); // 将cbuf转存入result 
    (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0); // 释放int数组元素 
    return result; 
} </span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值