2017-05-31 19:46:42 sinat_36246371 阅读数 1996

图像取反相当于取底片,对于每个像素点的RGB来讲,就是:

R=255R
G=255G
B=255B

用R’,G’,B’来替换R,G,B。

直接上图吧,假如原图像是这样的:


这里写图片描述

那么处理后的图像就是这样的:


这里写图片描述

代码实现如下:

import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;

public class ImageNegative {
    public static void main(String args[]) throws IOException {
        BufferedImage image = null;
        File f = null;

        try {
            f = new File("E:\\In.jpg");
            image = ImageIO.read(f);

            int width = image.getWidth();
            int height = image.getHeight();

            for (int j = 0; j < height; j++) {
                for (int i = 0; i < width; i++) {
                    int p = image.getRGB(i, j);
                    int a = (p >> 24) & 0xff;
                    int r = (p >> 16) & 0xff;
                    int g = (p >> 8) & 0xff;
                    int b = p & 0xff;

                    r = 255 - r;
                    g = 255 - g;
                    b = 255 - b;

                    p = (a << 24) | (r << 16) | (g << 8) | b;
                    image.setRGB(i, j, p);
                }
            }

            f = new File("E:\\Out.jpg");
            ImageIO.write(image, "jpg", f);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
2019-10-09 20:40:10 weixin_40198377 阅读数 210

包括图像的读入、显示、保存,获取图片大小、通道数等属性,求取图像均值、标准差,遍历图像各个像素,图像取反,图像色彩空间转换,提取某种颜色,通道分离与合并等

1.基本操作

  • (1)读入图像
# 默认的读入格式是BGR
img1 = cv2.imread('E:/PycharmProjects/one.jpg')
  • (2)显示图像
cv2.imshow(‘winname’, img)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imshow(winname, mat) 有窗口名和图片两个参数,不要忘记第一个参数
cv2.waitKey(delay: Any = None) 等待键盘输入。参数为延迟时间,单位为ms。参数为0时表示一直等到有键盘任意输入再进行下一操作。

  • (3)保存图像
cv2.imwrite('E:/PycharmProjects/one.png', img1)

cv2.imwrite(filename, img) 有文件名和图片两个参数,通过设定文件名的后缀可以转换图片格式

  • (4)获取图片属性
def img_info(img):
    print('type:', type(img))
    print('img.size:', img.size)
    print('img.dtype:', img.dtype)
    print('img.shape', img.shape)
img_info(img1)

type( ): 获取对象类型,图像类型为numpy.ndarray
.shape: h, w, c 高度、宽度、通道数,最常用
.size: 图像像素总数
.dtype: 数据类型,默认为uint8

  • (5)图像求均值、标准差
mean_img = cv2.mean(img)
m, stddev = cv2.meanStdDev(img)

图像有三个通道时,结果为三个通道分别求均值和标准差

  • (6)遍历图像各个像素且取反
import cv2
import numpy as np
img1 = cv2.imread('E:/PycharmProjects/one.jpg')
def reverse_img(img):
    h, w, c = img.shape
    r_img = np.ones([h, w, c], dtype=np.uint8)#要注意dtype为np.uint8,否则图像无法正常显示
    print(r_img.dtype)
    print(r_img)
    print(r_img.shape)
    for row in range(h):
        for col in range(w):
            for ch in range(c):
                r_img[row, col, ch] = 255-img[row, col, ch]
    print(r_img.dtype)
    show('reverse_img', r_img)

reverse_img(img1)
  • (7)图像取反
ot_img1 = cv2.bitwise_not(img1)
  • (8)图像色彩空间转换
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

HSV(Hue, Saturation, Value)色彩空间,H(色调),S(饱和度),V(明度)

  • (9)提取图像中某种颜色
low = np.array([0, 0, 0])
up = np.array([255, 100, 100])
blue_img1 = cv2.inRange(img1, low, up)
cv2.inRange(src: Any, lowerb: Any, upperb: Any, dst: Any = None)

lowerb, upperb: numpy.ndarray类型

HSV基本颜色分量范围:HSV基本颜色分量范围

  • (10)通道分离与合并
b, g, r = cv2.split(img)
merge_img = cv2.merge([b, g, r])

2.代码示例

import cv2
import numpy as np

# 1.读入图片和保存图片
img1 = cv2.imread('E:/PycharmProjects/one.jpg')

# 2.显示图片
def show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
show('img1', img1)

# 3.保存图像
cv2.imwrite('E:/PycharmProjects/one.png', img1)

# 4.获取图片属性
def img_info(img):
    print('type:', type(img))
    print('img.size:', img.size)
    print('img.dtype:', img.dtype)
    print('img.shape', img.shape)
img_info(img1)

# 5.图像求均值、标准差
def mean_dev(img):
    mean_img = cv2.mean(img)
    print('mean', mean_img)
    m, stddev = cv2.meanStdDev(img)
    print('m', m, '\n', 'StdDev', stddev)
mean_dev(img1)

# 6.遍历图像各个像素且取反(有问题)
def reverse_img(img):
    h, w, c = img.shape
    r_img = np.zeros([h, w, c])
    for row in range(h):
        for col in range(w):
            for ch in range(c):
                r_img[row, col, ch] = 255-img[row, col, ch]
    show('reverse_img', r_img)

# reverse_img(img1)

# 7.openCV取反函数
def not_img(img):
    not_img = cv2.bitwise_not(img)
    show('not_img', not_img)
not_img(img1)

# 8.图像色彩空间转换
def color_cvt_img(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    show('gray', gray)
    show('hsv', hsv)
color_cvt_img(img1)

# 9.对图片的某种颜色进行提取
def color_inrange(img):
    low = np.array([0, 0, 0])
    up = np.array([255, 100, 100])
    blue_img1 = cv2.inRange(img1, low, up)
    show('blue_img1', blue_img1)
color_inrange(img1)


# 10.通道分离、合并
def img_channel(img):
    b, g, r = cv2.split(img)
    show('blue', b)
    print('blue.shape', b.shape)
    merge_img = cv2.merge([b, g, r])
    show('merge_img', merge_img)
img_channel(img1)

3.结果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2019-11-13 19:22:15 BOTAK_ 阅读数 19

图像的形态学处理

二值的形态学图像处理

首先先看两种不同的数学集合操作

  1. 取反操作
    Ac={xxA}A^c = \lbrace x | x\notin A\rbrace
  2. 位移操作
    Ax={yy=a+x,aA} A_x = \lbrace y|y=a+x,a\in A \rbrace

形态学处理图像操作

在了解形态学基本处理操作前,先了解几个概念
1,结构化要素(Structure Element),通常简称为SE,这个概念理解起来很简单,可以类比卷积运算中的Kernel,也就是卷积核,这个东西和卷积核不同点在于kernel默认了kernel center在正中心,而SE的center不一定在正中间,这样就使得SE具有一定的方向性
而且,下面的内容全部都是基于二值化图像进行的操作。

1,膨胀 Binary Dilation

D(F,K)=FK=bK({a+baF})D(F,K) = F \oplus K = \bigcup_{b \in K }(\lbrace a+b|a\in F\rbrace)
这个公式看起来很复杂,表述的是对于任意属于原图像F的点a和属于一个结构化要素的K中的任意一个点进行平移操作,得到一系列的新的图像集合,然后将这些图像集合取交集,就得到了Dilation之后的图像

2,腐蚀 Binary Erosion

E(F,K)=FK=bK({abaF})E(F,K) = F \ominus K = \bigcap_{b \in K}(\lbrace a-b|a \in F \rbrace)
Dilation and Erosion 是不可逆的操作

3,开操作 Binary Opening

O(F,K)=FK=(FK)KO(F,K) = F \circ K = (F \ominus K)\oplus K
清除比SE小的区域

4,闭操作 Binary Closeing

C(F,K)=FK=(FK)KC(F,K) = F \cdot K = (F \oplus K) \ominus K
类似于填海造田

5,细化
6,粗化
7,对偶性

二值形态学的相关算法

1,Hit-and-Miss

FK=(FK1)(FcK2)cF \otimes K = (F \ominus K_1) \bigcap (F^c \ominus K_2 )^c
K1K2=ΦK_1 \bigcup K_2 = \Phi and K1K,K2KK_1 \in K , K_2 \in K

Pattern Spectrum

这个概念类似于histogram,可以分割出来图像中不同大小的目标
PSrik(F) PSrik(F)

Recursive Dilation

FiK={Fi=0(Fi1K)Ki>=1F \bigoplus^i K =\begin{cases} F& \text{i=0}\\ (F\bigoplus^{i-1}K)\bigoplus K& \text{i>=1} \end{cases}

Recursive Erosion

FiK={Fi=0(Fi1K)Ki>=1F \ominus^i K =\begin{cases} F& \text{i=0}\\ (F\ominus^{i-1}K)\ominus K& \text{i>=1} \end{cases}

Distance Transfrom

根据连续的腐蚀操作就可以得到关于形态学中距离的概念,第一次使用SE腐蚀掉的距离设置成为1,第二次经过SE腐蚀掉的像素的距离设置为2,以此迭代,直到所有的像素被腐蚀完毕。所得到的就是原图像在形态学中的距离矩阵
rikr_ik是SE的尺寸

Skeleton

骨架,骨架就是距离边缘最远的像素的集合,与距离矩阵联系起来就是,距离矩阵中的每一个元素i,取一个i^2的矩阵,若这个矩阵中没有比它大的距离,则保留,反之,舍弃。

Skeleton Subset

i表示正在使用的SE的尺寸
K:SE
Si(F)=(FriK[(FriK)]K)S_i(F) = (F\ominus r_iK - [(F\ominus r_iK)] \circ K)

Skeleton

S(F)=i=0n(Si(F))S(F) = \bigcup_{i=0}^n(S_i(F))

Skeleton Reconstruction

F=i=0n(Si(F)riK)F = \bigcup_{i=0}^n (S_i(F)\oplus r_iK)

灰度的形态学图像处理

F:原图像。K:SE

GrayScale Dilation

Dg(F,K)=FgK=max[a,bK] {F(m+a,n+b)+K(a,b)}D_g(F,K) = F \oplus_g K = max_{[a,b \in K]}\ \lbrace F(m+a,n+b) + K(a,b) \rbrace
例子:一个简短的直线在histogram图上进行平移操作,取最大值

GrayScale Erosion

Eg(F,K)=FgK=min[a,bK] {F(ma,nb)K(a,b)}E_g(F,K) = F \ominus_g K = min_{[a,b \in K]}\ \lbrace F(m-a,n-b) - K(a,b) \rbrace
例子:一个简短的直线在histogram图上进行平移操作,取最小值

GrayScale Opening

Og(F,K)=FgK=(FgK)gKO_g(F,K) = F \circ_g K = (F \ominus_g K)\oplus_g K
例子:一个矩形从一个直方图下面进行向上匹配,能进入的保留,不能进入的删除。就像是雪人融化。

GrayScale Closing

Cg(F,K)=FgK=(FgK)gKC_g(F,K) = F \cdot_g K = (F \oplus_g K)\ominus_g K
例子:一个矩形从一个直方图上面进行向下匹配,能进入的保留,不能进入的删除。就像是沙漠中的风沙填埋凹区

分水岭算法

受限制的膨胀

原图像:M
限制图像:V
SE:K
提出的背景:一般而言,我们在对一个图像进行降噪处理的时候,往往也会模糊掉一些需要保留的细节,这时候,就需要对处理过后的图像进行相关的一些操作,去得到和原图像中真实内容最接近的那个图像。这就提出了受限制的膨胀算法。算法思想如下:
原图像假设用膨胀操作进行降噪,得到处理过后的图像G
G=MK1G = M \oplus K_1
然后利用SE K 进行i次的膨胀操作,但是膨胀的时候又可能膨胀之后的图像的内容会超过原始图像中内容的边界,这时候,就要用V对他做限制,一般是用处理后的图像与原图像做交集,知道不在变化。

2019-11-19 12:51:34 qq_29598161 阅读数 9

要求

对一副图像进行傅立叶变换,显示频谱,取其5,50,150为截至频率,进行频率域平滑,锐化,显示图像

待处理图像:

在这里插入图片描述

傅里叶变换和反变换

使用numpy包,进行二维傅里叶变换并将FFT的DC分量移到频谱中心:

def fft(image):
    f = np.fft.fft2(image)
    # move to center
    fshift = np.fft.fftshift(f)
    return fshift

使用numpy包,先将DC分量移回,再进行二维傅里叶反变换,为了图像正常显示,取了绝对值:

def ifft(fshift):
    f1shift = np.fft.ifftshift(fshift)
    image_back = np.fft.ifft2(f1shift)
    image_back = np.abs(image_back)
    return image_back

调用:

img = cv2.imread('4_29_a.jpg', 0)
plt_show_opcv("image", img)

fft_re = fft(img)
show_re = np.log(np.abs(fft_re))
plt_show_opcv("show_re", show_re)

image_back= ifft(fft_re)
plt_show_opcv("image_back", image_back)

结果:

在这里插入图片描述

频率域滤波

平滑-理想低通滤波

得到理想低通滤波模板:

def get_mask(shape, r):
    mask_ = np.zeros(shape, np.uint8)
    cv2.circle(mask_, (int(shape[1] / 2), int(shape[0] / 2)), r, 255, -1)
    return mask_

使用模板进行滤波:

img = cv2.imread('4_29_a.jpg', 0)
plt_show_opcv("image", img)

fshift_re = fft(img)
show_re = np.log(np.abs(fshift_re))
plt_show_opcv("show_re", show_re)

mask = get_mask(img.shape, 40)
plt_show_opcv("mask", mask)
re = fshift_re * mask

new_img = ifft(re)
plt_show_opcv("image_back", new_img)

半径5:
在这里插入图片描述
在这里插入图片描述
半径50:
在这里插入图片描述
在这里插入图片描述
可以大致看到轮廓:
半径150:
在这里插入图片描述
和原图差不多

锐化-巴特沃斯高通滤波

d为频率距原点的距离为

def bhpf(image, d):
    f = np.fft.fft2(image)
    fshift = np.fft.fftshift(f)
    transfor_matrix = np.zeros(image.shape)
    M = transfor_matrix.shape[0]
    N = transfor_matrix.shape[1]
    for u in range(M):
        for v in range(N):
            D = np.sqrt((u - M / 2) ** 2 + (v - N / 2) ** 2)
            filter_mat = 1 / (1 + np.power(d / D, 2))
            transfor_matrix[u, v] = filter_mat
    new_img = np.abs(np.fft.ifft2(np.fft.ifftshift(fshift * transfor_matrix)))
    return new_img

d距离为5:
在这里插入图片描述
d距离为50:
在这里插入图片描述
d距离为150:
在这里插入图片描述

参考

图像频域滤波与傅里叶变换
理想滤波 巴特沃兹滤波 高斯滤波

2017-05-31 20:15:26 sinat_36246371 阅读数 8292

从前面的文字中就可以看出,对数字图像的处理都是在像素级上操作的,准确地讲是操作像素点的RGB值,在图像取反灰度图像转换两篇中已经涉及到了对RGB操作的相关代码,相信大家已经也看到了,就是这一段:

for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
        int p = image.getRGB(i, j);

        int a = (p >> 24) & 0xff;
        int r = (p >> 16) & 0xff;
        int g = (p >> 8) & 0xff;
        int b = p & 0xff;

        p = (a << 24) | (r << 16) | (g << 8) | b;

        image.setRGB(i, j, p);
    }
}

其中这里的变量r,g,b就是对应的rgb值,那为什么要这样操作呢?先看一个图:


这里写图片描述

有了这个图相信大家就都看明白了,首先p是一个32位的二进制数,可以通过getRGB()方法得到,那么最前面的8位是alpha,后面依次是Red,Green,Blue。所以这就是代码中移位操作的意义,当然最后还要回归到原来的结构,那就用(a << 24) | (r << 16) | (g << 8) | b再拼装一次。

所以对图像中像素点的操作就可以这么写啦,后面具体是增强还是锐化,都是基于这样的操作做的。

没有更多推荐了,返回首页