2017-11-27 19:32:40 xjh_shin 阅读数 8052
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4118 人正在学习 去看看 贾志刚

一张图片放大以后就会呈现一个个的点阵,每一个点就是一个像素点,通过我们对RGB的颜色配比就可以显示出不同的颜色效果了,所以说最终我们想对一个图像进行处理的话就是对一个个像素点进行处理。
最著名的就是以下几种效果,我们分别在ImageHelper中加入了handleImageNegative方法,handleImagePixelsOldPhoto方法以及handleImagePixelsRelief方法,其实这三个方法没有什么区别只是对每一个像素点的RGBA的处理有所改变:
底片效果:其实说白了就是把每个点的RGB都让他被255减去(255-R,255-G,255-B),这样处理以后就可以得到底片效果了。

public static Bitmap handleImageNegative(Bitmap bm) {
    int width = bm.getWidth();
    int height = bm.getHeight();
    int color;//存取当前像素点的颜色
    int R, G, B, A;//存取当前像素点的RGBA
    Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    int[] oldPx = new int[width * height];
    int[] newPx = new int[width * height];
    bm.getPixels(oldPx, 0, width, 0, 0, width, height);//存储像素点的数组,起点需要偏移的量,读取数组的行距,第一次读取像素点的坐标(x,y),读取的长度,读取的宽度
    for (int i = 0; i < width * height; i++) {
        color = oldPx[i];
        //分离出RGBA四个分量
        R = Color.red(color);
        G = Color.green(color);
        B = Color.blue(color);
        A = Color.alpha(color);
        R = 255 - R;
        G = 255 - G;
        B = 255 - B;
        if (R > 255) {
            R = 255;
        } else if (R < 0) {
            R = 0;
        }
        if (G > 255) {
            G = 255;
        } else if (G < 0) {
            G = 0;
        }
        if (B > 255) {
            B = 255;
        } else if (B < 0) {
            B = 0;
        }
        newPx[i] = Color.argb(A, R, G, B);
    }
    bmp.setPixels(newPx, 0, width, 0, 0, width, height);
    return bmp;
}

老照片效果(就是之前博客的那个效果):
newR = (int) (0.393 * r + 0.769 * g + 0.189 * b);
newG = (int) (0.349 * r + 0.686 * g + 0.168 * b);
newB = (int) (0.272 * r + 0.534 * g + 0.131 * b);

public static Bitmap handleImagePixelsOldPhoto(Bitmap bm) {
    Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),
            Bitmap.Config.ARGB_8888);
    int width = bm.getWidth();
    int height = bm.getHeight();
    int color = 0;
    int r, g, b, a, r1, g1, b1;

    int[] oldPx = new int[width * height];
    int[] newPx = new int[width * height];

    bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);
    for (int i = 0; i < width * height; i++) {
        color = oldPx[i];
        a = Color.alpha(color);
        r = Color.red(color);
        g = Color.green(color);
        b = Color.blue(color);

        r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b);
        g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b);
        b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b);

        if (r1 > 255) {
            r1 = 255;
        }
        if (g1 > 255) {
            g1 = 255;
        }
        if (b1 > 255) {
            b1 = 255;
        }

        newPx[i] = Color.argb(a, r1, g1, b1);
    }
    bmp.setPixels(newPx, 0, width, 0, 0, width, height);
    return bmp;
}

浮雕效果:B.R=C.R-B.R+127;B.G=C.G-B.G+127;B.B=C.B-B.B+127;(C为前一个点的原RGBA的值)

public static Bitmap handleImagePixelsRelief(Bitmap bm) {
    Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),
            Bitmap.Config.ARGB_8888);
    int width = bm.getWidth();
    int height = bm.getHeight();
    int color = 0, colorBefore = 0;
    int a, r, g, b;
    int r1, g1, b1;

    int[] oldPx = new int[width * height];
    int[] newPx = new int[width * height];

    bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);
    for (int i = 1; i < width * height; i++) {
        colorBefore = oldPx[i - 1];
        a = Color.alpha(colorBefore);
        r = Color.red(colorBefore);
        g = Color.green(colorBefore);
        b = Color.blue(colorBefore);

        color = oldPx[i];
        r1 = Color.red(color);
        g1 = Color.green(color);
        b1 = Color.blue(color);

        r = (r - r1 + 127);
        g = (g - g1 + 127);
        b = (b - b1 + 127);
        if (r > 255) {
            r = 255;
        }
        if (g > 255) {
            g = 255;
        }
        if (b > 255) {
            b = 255;
        }
        newPx[i] = Color.argb(a, r, g, b);
    }
    bmp.setPixels(newPx, 0, width, 0, 0, width, height);
    return bmp;
}

然后就可以显现出来了,这部分因为颜色处理的算法是确定的所以把上面的看懂了就能搞懂了,我就把效果给大家看下吧,布局文件和活动的代码特别简洁就不贴上来了。
像素点

项目GitHub地址:传送门

2019-01-10 21:54:51 a369189453 阅读数 341
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4118 人正在学习 去看看 贾志刚

1 基于图像单像素点的处理

看过数字图像处理一书的都知道,图像处理中基于像素点的处理分为两种
灰度变换:本质就是基于单像素点的变化处理。
空间滤波:本质就是基于邻域像素点的变化处理。
今天要讲的是在OpenCv下基于基于单像素点的处理,其中会讲到OpenCv针对单像素处理封装好的一些ApI,即实质原理。

1.1 图像像素点的访问

要进行基于单像素点的处理,首先就必须知道,给你一幅图,你如何去访问图中的每一个像素点。无论是网上还是各种教程书上都给出了三种访问像素点的方式,分别是:
1、 指针访问。实质就是通过数据指针直接访问数据。
2、 迭代器访问。类似STL中容器的访问。
3、 动态地址计算。将每个像素转换为对应类型(uchar或Vec3b),再进行访问。
下面以为图像中每个像素点加1为例说明三种方法。

/************************************************/
/*访问图像像素点的三种方法
/************************************************/
	int rows = img.rows;
	int cols = img.cols;
	int channels = img.channels();
	uchar *pRow = 0;

// 方法一:指针法访问
	for (int i = 0; i < rows; ++i)
	{
		// 获取行指针
		pRow = img.ptr<uchar>(i);
		for (int j = 0; j < cols; ++j)
		{
			if (channels == 1) //单通道
			{
				pRow[j] = pRow[j] + 1;
			}
			else if (channels == 3) //三通道
			{
				pRow[j * 3 ] = pRow[j * 3 ] + 1;
				pRow[j * 3 + 1] = pRow[j * 3 + 1] + 1;
				pRow[j * 3 + 2] = pRow[j * 3 + 2] + 1;
			}
		}
	}

// 方法一:迭代器法访问、事先得知道图像通道数,这里假设为3通道
	Mat_<Vec3b>::iterator it = img.begin<Vec3b>(); //初始位置迭代器
	Mat_<Vec3b>::iterator end = img.end<Vec3b>(); //终止位置迭代器
	for (; it != end; ++it)
	{
		(*it)[0] = (*it)[0] + 1;
		(*it)[1] = (*it)[1] + 1;
		(*it)[2] = (*it)[2] + 1;
	}

// 方法一:动态地址访问、事先得知道图像通道数,这里假设为3通道
	for (int i = 0; i < rows; ++i)
	{
		for (int j = 0; j < cols; ++j)
		{
			if (channels == 1) //单通道
			{
				img.at<uchar>(i,j) = img.at<uchar>(i, j)+1;
			}
			else if (channels == 3) //三通道
			{
				img.at<Vec3b>(i, j)[0] = img.at<Vec3b>(i, j)[0] + 1;
				img.at<Vec3b>(i, j)[1] = img.at<Vec3b>(i, j)[1] + 1;
				img.at<Vec3b>(i, j)[2] = img.at<Vec3b>(i, j)[2] + 1;
			}
		}
	}

1.2 图像亮度和对比度调整

知道如何对图像单像素点进行操作后,其实就可以对图像进行很多操作了,其中最有用,最让人产生直观感受的就是亮度和对比度的调整了。
基于单像素点变换分为以下几种:r为源像素点值,s为变换后像素点值。这里的值有可能是灰度图像中的灰度值,RGB颜色模型中的红、绿、蓝分量值,或者是HSV颜色模型中的色调、饱和度、亮度值。
1、 翻转变换

s=L-1-r
2、 线性变换
s=a*r+b
作用:a控制对比度,b控制亮度。 3、 对数变化
s=clog(1+r)
作用:围较窄的低灰度值映射到范围较宽的灰度区间,同时将范围较宽的高灰度值区间映射为较窄的灰度区间,从而扩展了暗像素的值,压缩了高灰度的值,能够对图像中低灰度细节进行增强。 4、幂(伽马)变换
s=cr^γ
作用: 当γ=c=1时:恒等变换。 当c=1,γ<1时:扩展低灰度级范围,压缩高灰度级范围,灰度值整体增大,变亮。γ 的值越小,对图像低灰度值的扩展越明显。 当c=1,γ>1时:压缩低灰度级范围,扩展高灰度级范围,灰度值整体减小,变暗。γ的值越大,对图像高灰度值部分的扩展越明显。 伽马变换主要用于图像的校正,对灰度值过高(图像过亮)或者过低(图像过暗)的图像进行修正,增加图像的对比。 值得注意的是上述4个变换中,除了翻转变换结果不可能溢出,即值在范围0-255之间,其他的都有可能溢出,特别是线性变换还可能出现负值。下面就以线性变换为例写一个小例子。例子是基于QT的,但不妨碍理解。
主要源码:
void QtGuiApplication1::update()
{
	int rows = m_Sor.rows;
	int cols = m_Sor.cols;
	int channels = m_Sor.channels();
	uchar *pSorRow = 0;
	uchar *pDstRow = 0;

	float contrast = m_Value1 / 10.f;
	// 方法一:指针法访问
	for (int i = 0; i < rows; ++i)
	{
		// 获取行指针
		pSorRow = m_Sor.ptr<uchar>(i);
		pDstRow = m_Dst.ptr<uchar>(i);
		for (int j = 0; j < cols; ++j)
		{
			if (channels == 1) //单通道
			{
				pDstRow[j] = pSorRow[j] + 1;
			}
			else if (channels == 3) //三通道
			{
				pDstRow[j * 3] = saturate_cast<uchar>(pSorRow[j * 3]* contrast + m_Value2);
				pDstRow[j * 3 + 1] = saturate_cast<uchar>(pSorRow[j * 3 + 1] * contrast + m_Value2);
				pDstRow[j * 3 + 2] = saturate_cast<uchar>(pSorRow[j * 3 + 2] * contrast + m_Value2);
			}
		}
	}

	//normalize(m_Dst, m_Dst, 0, 255,NORM_MINMAX);
	imshow("Dst", m_Dst);
}
使用到的opencv API:
saturate_cast(v)

作用:将输入值V限制在给定类型T范围内。

normalize()

void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
参数:src:输出数组。
dst:输出数组。
alpha:参数。
beta:参数。
norm_type:类型。
dtype:输出数组的元素类型。默认和src一致。
mask:是否对src中的指定元素变换,默认全部元素变换。
norm_type取值:
在这里插入图片描述
作用:归一化函数,将数值限制在指定范围内,值得注意的是该函数支持输入值为负数哟。对数变换和指数变换后都需要使用该函数进行范围限制。

1.3 颜色空间缩减

什么是颜色空间缩减,目前我们接触到的图像都是256个灰度值的图像,对于显示来说自然是灰度值等级越多,图像越细腻,但是进行图像处理的时候可不是灰度值等级越多越好,而是适当就行,什么是适合呢?是100个灰度等级还是10个灰度等级,这得要具体情况具体对待了。
颜色空间缩减非常简单,一个公式就能明白,例如我们要把256个灰度级缩减到26个灰度级,那么
s=r/10*10
即对每个像素点都进行上述变换,那么一幅256个灰度级的图像最终就变为26个灰度级的图像。
为了提高提高变换的效率,这里可使用查表法,就是预先把每个灰度值将要变换为的灰度值体现算好,放在表中,变换时直接查表。Opencv提供了一个现成的API专门处理的这种查表式变换。

源码例子:
#include "QtGuiApplication1.h"

//#define Ui
#ifndef Ui

#include <QFileInfo>
#include <QDir>
#include <opencv2\opencv.hpp>
using namespace cv;

#else

#include <QtWidgets/QApplication>

#endif

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);

#ifdef Ui
	QtGuiApplication1 w;
	w.show();
	return a.exec();
#else
	QString path = QFileInfo(QCoreApplication::applicationDirPath(), "../../../../../").absoluteDir().absolutePath() + "/imgs/";
	Mat src = imread(path.toStdString() + "sor1.jpg", IMREAD_GRAYSCALE);
	imshow("src", src);

	int divideWith = 50;
	Mat table(1,256,CV_8U);
	for (int i = 0; i < 256; ++i)
	{
		table.data[i] = (i / divideWith) * divideWith;
	}

	Mat dst;
	LUT(src, table, dst);
	imshow("dst", dst);
	waitKey();

	return 0;
#endif
	
}

效果图:明显灰度级较少之后,图片变得很粗糙了。
在这里插入图片描述

2018-08-18 15:59:39 zhaohaibo_ 阅读数 4974
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4118 人正在学习 去看看 贾志刚

这篇文章记录python像素处理的基本方法方法

做的是14年的建模A题嫦娥登陆。

其中一个问题是这样的

如何选择下面这个图(月球表面高度2400米处的照片)的嫦娥三号着陆点?

在这里插入图片描述

1. 读取图像

from scipy import misc
from scipy.misc import imread, imresize, imsave
import os
import seaborn as sns
import matplotlib.pyplot as plt
os.chdir('/Users/zhaohaibo/Desktop')

# 读取图像
pic = imread('pic2400.jpg')
pic.shape  # (2300,2300)
pic.max()  # 218
pic.min() # 0
pic.dtype # dtype('uint8')


# 使用sbs的palette变成一个带有颜色的图(目的?不知道。。)
sns.set()
sns.set_style("white")
pic2 = plt.imshow(pic)
plt.savefig('24003.jpg')

在这里插入图片描述

2.使用K-Means聚类
  • img = cv2.imread(‘图片’)之后,直接就可以查看每个点的像素值
  • 聚为8类,想象中大致就可以把平地那一类选出来了吧
import numpy as np
import cv2
from scipy import misc
from scipy.misc import imread, imresize, imsave
import os
import seaborn as sns
import matplotlib.pyplot as pl
os.chdir('/Users/zhaohaibo/Desktop')

#对rgb图像kmeans聚类
img = cv2.imread('24003.jpg')
Z = img.reshape((-1,3))

# convert to np.float32
Z = np.float32(Z)

# define criteria, number of clusters(K) and apply kmeans()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 8
ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)

# Now convert back into uint8, and make original image
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))
cv2.imwrite('k=8.jpg',res2)

分别是彩色和黑白的聚类结果。

在这里插入图片描述

在这里插入图片描述

# 划出平地
from PIL import Image
i = 1
j = 1
img = Image.open("k=12.jpg")#读取系统的内照片
print (img.size)#打印图片大小
print (img.getpixel((4,4)))
# 要保留177 22 88
width = img.size[0]#长度
height = img.size[1]#宽度
for i in range(0,width):#遍历所有长度的点
    for j in range(0,height):#遍历所有宽度的点
        data = (img.getpixel((i,j)))#打印该图片的所有点
        print (data)#打印每个像素点的颜色RGBA的值(r,g,b,alpha)
        print (data[0])#打印RGBA的r值
        if (data[0]>=170 and data[0]<=180):#RGBA的r值大于170,并且g值大于170,并且b值大于170
            img.putpixel((i,j),(255,255,255,255))#则这些像素点的颜色改成白色
img = img.convert("RGB")#把图片强制转成RGB
img.save("1.jpg")#保存修改像素点后的图片

在这里插入图片描述

好像有点意思了,看起来平地被标成了白色。

提取rgb数值(想画3D图没成功)

法1
# 提取rgb的数值
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
from PIL import Image
import os
os.chdir("/Users/zhaohaibo/Desktop")
i = 1
j = 1
img = Image.open("k=12.jpg")#读取系统的内照片
print (img.size)#打印图片大小
print (img.getpixel((4,4)))  # 获取某点的像素值
# 要保留177 22 88
width = img.size[0]#长度
height = img.size[1]#宽度
x = []
y = []
z = []
for i in range(0,width):#遍历所有长度的点
    for j in range(0,height):#遍历所有宽度的点
        data = (img.getpixel((i,j)))
        x.append(data[0])
        y.append(data[1])
        z.append(data[2])
x = np.array(x)
y = np.array(y)
z = np.array(z)
x = x.reshape(214,215)
y = y.reshape(214,215)
z = z.reshape(214,215)


网上找了另一个简单的方法
image_path = "HOPE.png"

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot
from PIL import Image

fig = pyplot.figure()
axis = fig.add_subplot(1, 1, 1, projection="3d") # 3D plot with scalar values in each axis

im = Image.open(image_path)
r, g, b = list(im.getdata(0)), list(im.getdata(1)), list(im.getdata(2))

axis.scatter(r, g, b, c="#ff0000", marker="o")
axis.set_xlabel("Red")
axis.set_ylabel("Green")
axis.set_zlabel("Blue")
pyplot.show()
选择最佳着陆点
# 提取rgb的数值
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
from PIL import Image
import os
os.chdir("/Users/zhaohaibo/Desktop")

img = Image.open("face.jpg")
width = img.size[0]#长度
height = img.size[1]#宽度
def pi(i,j):
    return img.getpixel((i,j))[0]
for i in range(6, height-6):
    for j in range(6, width-6):
        if(pi(i,j)==255 and pi(i+5,j+5)==255 and pi(i-5,j-5)==255 and pi(i-5,j+5)==255 and pi(i+5,j-5)==255):
            img.putpixel((i,j),(0,255,0,255))
img = img.convert("RGB")
def check_pi(i,j):
    if(img.getpixel((i,j))==(0,255,0)):
        return True
    else:
        return False
for i in range(2, height-2):
    for j in range(2, width-2):
        if(check_pi(i,j) and check_pi(i-2,j-2) and check_pi(i-2,j+2) and check_pi(i+2,j-2) and check_pi(i+2,j+2)):
            img.putpixel((i,j),(0,0,255,255))
area = []
for i in range(2,height-2):
    for j in range(2,width-2):
        if(img.getpixel((i,j))==(0,0,255)):
            area.append((i,j))
for i in range(len(area)-6):
    if(area[i-7][0]==area[i+6][0]):
        print((area[i]))
(167, 48)

在这里插入图片描述

所以一些绿色点是好的着陆区域?绿色点里面蓝色点是好的着陆点?

2019-01-17 16:56:15 qq_34814092 阅读数 1016
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4118 人正在学习 去看看 贾志刚

Java OpenCV-4.0.0 图像处理8 图像像素点的获取与操作

java OpenCV-4.0.0 获取图像像素点并对像素点进行操作

package com.xu.image;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

/**  
 * 
 * @Title: OpenCV.java   
 * @Package com.xu.opencv   
 * @Description: TODO   
 * @author: xuhyacinth     
 * @date: 2019年1月17日 下午7:54:15   
 * @version V-1.0 
 * @Copyright: 2019 xuhyacinth
 *
 */
public class Test {

	static {
		//在使用OpenCV前必须加载Core.NATIVE_LIBRARY_NAME类,否则会报错
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
	}

	public static void main(String[] args) {
		getPixelImage();
	}

	/**
	 * OpenCV-4.0.0 获取图像像素点
	 * @return: void  
	 * @date: 2019年1月17日 下午8:24:07
	 */
	public static void getPixelImage_1() {
		Mat src = Imgcodecs.imread("C:\\Users\\Administrator\\Pictures\\0001.jpg");
		Mat dst = new Mat(src.size(),src.type());

		int channels = src.channels();//获取图像通道数
		double[] pixel = new double[3];//用于存放像素点

		for (int i = 0, rlen = src.rows(); i < rlen; i++) {
			for (int j = 0, clen = src.cols(); j < clen; j++) {
				if (channels == 3) {//图片为3通道即平常的(B,G,R)
					pixel = src.get(i, j).clone();
					pixel[0] = 255 - pixel[0];//B
					pixel[1] = 255 - pixel[1];//G
					pixel[2] = 255 - pixel[2];//R
					dst.put(i, j, pixel);
				} else {//图片为单通道
					dst.put(i, j, src.get(i, j).clone());
				}
			}
		}
		Imgproc.resize(src, src, new Size(src.cols()/2,src.rows()/2));
		HighGui.imshow("图片测试", dst);
		HighGui.waitKey(0);
	}

	/**
	 * OpenCV-4.0.0 获取图像像素点
	 * @return: void  
	 * @date: 2019年11月24日 下午8:24:07
	 */
	public static void getPixelImage_2() {
		Mat src = Imgcodecs.imread("C:\\Users\\Administrator\\Pictures\\0001.jpg");
		
		Mat dst = new Mat(src.size(),src.type());
		double[] pixel = new double[3];//用于存放像素点

		for (int i = 0 ,row = (int) src.size().height; i < row; i++) {
			for (int j = 0,col = (int) src.size().width; j < col; j++) {
				pixel = src.get(i, j).clone();
				pixel[0] = 255 - pixel[0];//B
				pixel[1] = 255 - pixel[1];//G
				pixel[2] = 255 - pixel[2];//R
				dst.put(i, j, pixel);
			}
		}
		HighGui.imshow("图片测试", dst);
		HighGui.waitKey(0);
	}

}


1

2018-01-19 19:49:15 fsx_xiaomei 阅读数 1582
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4118 人正在学习 去看看 贾志刚
上边两篇博文描述了利用ColorMatrix来处理图片,这篇文章讲如何改变图片的像素点的ARGB值,从而改变图片呈现效果。值得注意的是,我们是不能直接改变传递的原始图片的,一般是根据原始图片生成一张新的图片用来修改。
在Android中,系统提供了Bitmap.getPixels()方法来提取整个Bitmap中的像素点,并保存到第一个数组中,方法如下:
public void getPixels(@ColorInt int[] pixels, int offset, int stride,int x, int y, int width, int height)
//pixels---接收位图颜色值的数组
//offset---写入到pixels[]中的第一个像素索引值(即第一个像素要放在数组的那个位置)
//stride---pixels[]中的行间距
//x---从位图中读取的第一个像素的x坐标值
//y---从位图中读取的第一个像素的y坐标值(x,y确定从哪个像素点开始)
//width---从每一行中读取的像素宽度
//height---读取的行数

通常情况下,可以使用如下代码:
从第(0,0)个位置开始,一次获取原图所有点的像素值,一次放入数组oldArr中,第一个像素点的索引为0;

mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);

接下来就是利用代码获取每个像素具体的ARGB值,代码如下:

for (int i = 0; i < oldArr.length; i++) {
    index = oldArr[i];
    oldA = Color.alpha(index);//A:透明度
    oldR = Color.red(index);//R:红
    oldG = Color.green(index);//G:绿
    oldB = Color.blue(index);//B:蓝
}

获取到具体的颜色值后,就可以通过相应的算法修改它的ARGB值,从而得到一个新的像素,从而重构一张新的图像。例如下代码,将修改过的ARGB值合成一个新的像素:

newA = oldA;
newR = (int) (0.393 * oldR + 0.769 * oldG + 0.189 * oldB);
newG = (int) (0.349 * oldR + 0.686 * oldG + 0.168 * oldB);
newB = (int) (0.272 * oldR + 0.534 * oldG + 0.131 * oldB);
curArr[i] = Color.argb(newA, newR, newG, newB);//重构一个新像素

最后通过如下代码,将处理后的像素点数组重新set给Bitmap

curPic.setPixels(curArr, 0, width, 0, 0, width, height);
  • 常用像素点处理效果
    这些处理方法是某些专业人士发现的,当然我也没查过到底是谁哈。通过特定的算法对每个像素点进行处理,就可以得到不同的处理效果。

  • 底片效果

newR = 255 - oldR;
newG = 255 - oldG;
newB = 255 - oldB;

实现代码:

/**底片效果*/
private Bitmap getNegativePic() {
    int oldA, oldR, oldG, oldB, newA, newR, newG, newB;
    Bitmap curPic = Bitmap.createBitmap(width, height, Config.ARGB_8888);
    mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);//获取原图的像素值,将像素值放入oldArr中

    for (int i = 0; i < oldArr.length; i++) {
        index = oldArr[i];//依次获取某个像素点
        oldA = Color.alpha(index);//获取相应的ARGB值
        oldR = Color.red(index);
        oldG = Color.green(index);
        oldB = Color.blue(index);

        newA = oldA;
        newR = 255 - oldR;//做相应的处理,生成新的ARGB值
        newG = 255 - oldG;
        newB = 255 - oldB;

        //保证每个新的ARGB值的范围在0~255之间
        newR = (newR > 255 ? 255 : newR) < 0 ? 0 : (newR > 255 ? 255 : newR);
        newG = (newG > 255 ? 255 : newG) < 0 ? 0 : (newG > 255 ? 255 : newG);
        newB = (newB > 255 ? 255 : newB) < 0 ? 0 : (newB > 255 ? 255 : newB);
        //合成新的像素点,将新的像素点一次放入数组curArr
        curArr[i] = Color.argb(newA, newR, newG, newB);
    }
    //用curArr合成新的图片curPic
    curPic.setPixels(curArr, 0, width, 0, 0, width, height);
    return curPic;
}
  • 老照片效果
newR = (int) (0.393 * oldR + 0.769 * oldG + 0.189 * oldB);
newG = (int) (0.349 * oldR + 0.686 * oldG + 0.168 * oldB);
newB = (int) (0.272 * oldR + 0.534 * oldG + 0.131 * oldB);
  • 浮雕效果
index = oldArr[i - 1];
oldA = Color.alpha(index);
oldR = Color.red(index);
oldG = Color.green(index);
oldB = Color.blue(index);

index = oldArr[i];
newR = Color.red(index)
newG = Color.green(index);
newB = Color.blue(index);

newR = oldR - newR + 127;
newG = oldG - newG + 127;
newB = oldB - newB + 127;

运行效果:
这里写图片描述
代码:

/**
 * 常用像素点处理效果 获取一张图片的所有像素点 通过改变图片的每一个像素点来达到对应的处理效果 底片效果 老照片效果 浮雕效果
 * @author fanshenxia
 */
public class PixelsEffectActivity extends Activity implements OnClickListener {

    private ImageView mImg;
    private Button mBtnNevigation, mBtnOld, mBtnRelief;
    private Bitmap mBmp;
    private int[] oldArr, curArr;
    private int width, height, index;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_effect_pixels);

        init();
    }

    private void init() {
        mBmp = BitmapFactory.decodeResource(getResources(), R.drawable.boyimg);
        width = mBmp.getWidth();
        height = mBmp.getHeight();
        oldArr = new int[width * height];
        curArr = new int[width * height];

        mImg = findViewById(R.id.img_pixels);
        mBtnNevigation = findViewById(R.id.negative_pixels);
        mBtnOld = findViewById(R.id.old_pixels);
        mBtnRelief = findViewById(R.id.relief_pixels);

        mBtnNevigation.setOnClickListener(this);
        mBtnOld.setOnClickListener(this);
        mBtnRelief.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.negative_pixels:
            mImg.setImageBitmap(getNegativePic());
            break;
        case R.id.old_pixels:
            mImg.setImageBitmap(getOldPic());
            break;
        case R.id.relief_pixels:
            mImg.setImageBitmap(getReliefPic());
            break;
        }
    }

    /**
     * 底片效果
     * 
     * @return
     */
    private Bitmap getNegativePic() {
        int oldA, oldR, oldG, oldB, newA, newR, newG, newB;
        Bitmap curPic = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);

        for (int i = 0; i < oldArr.length; i++) {
            index = oldArr[i];
            oldA = Color.alpha(index);
            oldR = Color.red(index);
            oldG = Color.green(index);
            oldB = Color.blue(index);

            newA = oldA;
            newR = 255 - oldR;
            newG = 255 - oldG;
            newB = 255 - oldB;

            // newA = (newA>255?255:newA)<0?0:(newA>255?255:newA);
            newR = (newR > 255 ? 255 : newR) < 0 ? 0 : (newR > 255 ? 255 : newR);
            newG = (newG > 255 ? 255 : newG) < 0 ? 0 : (newG > 255 ? 255 : newG);
            newB = (newB > 255 ? 255 : newB) < 0 ? 0 : (newB > 255 ? 255 : newB);

            curArr[i] = Color.argb(newA, newR, newG, newB);
        }

        //将下部分的像素倒置
//      for (int i = oldArr.length / 2; i >= 0; i--) {
//          curArr[oldArr.length - i - 1] = curArr[i];
//      }
//
//      for (int i = height / 2; i < height; i++) {
//          for (int j = 0; j < width / 2; j++) {
//              int index = curArr[i * width + (width - j) - 1];
//              curArr[i * width + (width - j) - 1] = curArr[i * width + j - 1];
//              curArr[i * width + j - 1] = index;
//          }
//      }

        curPic.setPixels(curArr, 0, width, 0, 0, width, height);

        return curPic;
    }

    /**
     * 老照片效果
     * 
     * @return
     */
    private Bitmap getOldPic() {
        int oldA, oldR, oldG, oldB, newA, newR, newG, newB;
        Bitmap curPic = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);

        for (int i = 0; i < oldArr.length; i++) {
            index = oldArr[i];
            oldA = Color.alpha(index);
            oldR = Color.red(index);
            oldG = Color.green(index);
            oldB = Color.blue(index);

            newA = oldA;
            newR = (int) (0.393 * oldR + 0.769 * oldG + 0.189 * oldB);
            newG = (int) (0.349 * oldR + 0.686 * oldG + 0.168 * oldB);
            newB = (int) (0.272 * oldR + 0.534 * oldG + 0.131 * oldB);

            // newA = (newA>255?255:newA)<0?0:(newA>255?255:newA);
            newR = (newR > 255 ? 255 : newR) < 0 ? 0 : (newR > 255 ? 255 : newR);
            newG = (newG > 255 ? 255 : newG) < 0 ? 0 : (newG > 255 ? 255 : newG);
            newB = (newB > 255 ? 255 : newB) < 0 ? 0 : (newB > 255 ? 255 : newB);

            curArr[i] = Color.argb(newA, newR, newG, newB);
        }
        curPic.setPixels(curArr, 0, width, 0, 0, width, height);

        return curPic;
    }

    /**
     * 浮雕效果
     * 
     * @return
     */
    private Bitmap getReliefPic() {
        int oldA, oldR, oldG, oldB, newA, newR, newG, newB;
        Bitmap curPic = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);

        for (int i = 1; i < oldArr.length; i++) {
            index = oldArr[i - 1];
            oldA = Color.alpha(index);
            oldR = Color.red(index);
            oldG = Color.green(index);
            oldB = Color.blue(index);

            index = oldArr[i];
            newR = Color.red(index);
            newG = Color.green(index);
            newB = Color.blue(index);

            newR = oldR - newR + 127;
            newG = oldG - newG + 127;
            newB = oldB - newB + 127;

            newR = (newR > 255 ? 255 : newR) < 0 ? 0 : (newR > 255 ? 255 : newR);
            newG = (newG > 255 ? 255 : newG) < 0 ? 0 : (newG > 255 ? 255 : newG);
            newB = (newB > 255 ? 255 : newB) < 0 ? 0 : (newB > 255 ? 255 : newB);

            curArr[i] = Color.argb(oldA, newR, newG, newB);
        }
        curPic.setPixels(curArr, 0, width, 0, 0, width, height);

        return curPic;
    }

}

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView 
        android:id="@+id/img_pixels"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/boyimg"
        />

    <Button 
        android:id="@+id/old_pixels"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="老照片效果"
        />

    <Button 
        android:id="@+id/negative_pixels"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="底片效果"
        />


    <Button 
        android:id="@+id/relief_pixels"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="浮雕效果"
        />
</LinearLayout>

上面我注解了一段代码,是我想要将图片的上半部分弄个倒影的景象:

    //将下部分的像素倒置
//      for (int i = oldArr.length / 2; i >= 0; i--) {
//          curArr[oldArr.length - i - 1] = curArr[i];
//      }
//
//      for (int i = height / 2; i < height; i++) {
//          for (int j = 0; j < width / 2; j++) {
//              int index = curArr[i * width + (width - j) - 1];
//              curArr[i * width + (width - j) - 1] = curArr[i * width + j - 1];
//              curArr[i * width + j - 1] = index;
//          }
//      }

运行效果:
这里写图片描述

有趣的图像处理

阅读数 309

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