通过Mat操作每个像素,改变bgr三色的值大小。
以及"改变像素的位置",扩张和挤压。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 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 |
import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.opencv.core.Mat; import org.opencv.imgcodecs.Imgcodecs; public class SpotExpandExtrude extends JFrame { private JLabel imageView; private Mat srcMat; private int type = 1; private int mouseX; private int mouseY; private int radius = 30; private int divisor = 10; public SpotExpandExtrude() { JRadioButton spotBtn = new JRadioButton("手电筒"); spotBtn.setSelected(true); spotBtn.setBounds(15, 5, 80, 25); spotBtn.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { type = 1; spotPic(); } }); JRadioButton expandBtn = new JRadioButton("凸透镜"); expandBtn.setBounds(125, 5, 80, 25); expandBtn.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { type = 2; expandPic(); } }); JRadioButton extrudeBtn = new JRadioButton("凹透镜"); extrudeBtn.setBounds(235, 5, 80, 25); ButtonGroup group = new ButtonGroup(); group.add(spotBtn); group.add(expandBtn); group.add(extrudeBtn); JLabel radiusLabel = new JLabel("半径:" + radius); radiusLabel.setBounds(340, 10, 80, 15); JSlider valueBar = new JSlider(10, 400); valueBar.setValue(radius); valueBar.setBounds(400, 5, 150, 25); valueBar.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { radius = valueBar.getValue(); radiusLabel.setText("半径:" + radius); if (1 == type) { // 手电筒 spotPic(); } else if (2 == type) { // 凸透镜 expandPic(); } else { // 凹透镜 extrudePic(); } } }); JLabel divisorLabel = new JLabel("凹镜因子:" + divisor); divisorLabel.setBounds(340, 35, 90, 15); JSlider divisorBar = new JSlider(10, 50); divisorBar.setValue(divisor); divisorBar.setBounds(410, 30, 140, 25); divisorBar.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { divisor = divisorBar.getValue(); divisorLabel.setText("凹镜因子:" + divisor); if (1 == type) { // 手电筒 spotPic(); } else if (2 == type) { // 凸透镜 expandPic(); } else { // 凹透镜 extrudePic(); } } }); extrudeBtn.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { type = 3; radius = 220; // 针对本图片合适的一组数字 divisor = 15; // 针对本图片合适的一组数字 valueBar.setValue(radius); divisorBar.setValue(divisor); extrudePic(); } }); mouseX = 512 / 2; mouseY = 512 / 2; imageView = new JLabel(""); imageView.setBounds(0, 60, 512, 512); imageView.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { mouseX = e.getX(); mouseY = e.getY(); if (1 == type) { // 手电筒 spotPic(); } else if (2 == type) { // 凸透镜 expandPic(); } else { // 凹透镜 extrudePic(); } } }); this.setTitle("手电筒、凸透镜、凹透镜"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(550, 600); this.getContentPane().setLayout(null); this.getContentPane().add(spotBtn); this.getContentPane().add(expandBtn); this.getContentPane().add(radiusLabel); this.getContentPane().add(valueBar); this.getContentPane().add(extrudeBtn); this.getContentPane().add(divisorLabel); this.getContentPane().add(divisorBar); this.getContentPane().add(imageView); srcMat = Imgcodecs.imread("./lena.jpg"); //, Imgcodecs.CV_LOAD_IMAGE_COLOR); setIcon(srcMat); } // 黑天照手电筒效果 private void spotPic() { Mat dstMat = new Mat(srcMat.rows(), srcMat.cols(), srcMat.type()); for (int y = 0; y < srcMat.rows(); y++) { // 行,对应y轴 for (int x = 0; x < srcMat.cols(); x++) { // 列,对应x轴 double dx = Math.abs(x - mouseX); double dy = Math.abs(y - mouseY); double distance = Math.sqrt(dx * dx + dy * dy); // 像素距离鼠标点击位置的距离 double weight = Math.exp(distance / radius * -1d); // 归一化。距离越近的越趋向于1。 double[] pixel = srcMat.get(y, x); pixel[0] = Math.round(pixel[0] * weight); // weight越趋向1,越接近原色彩 pixel[1] = Math.round(pixel[1] * weight); pixel[2] = Math.round(pixel[2] * weight); dstMat.put(y, x, pixel); } } setIcon(dstMat); } // 凸透镜 private void expandPic() { Mat dstMat = srcMat.clone(); for (int y = 0; y < srcMat.rows(); y++) { for (int x = 0; x < srcMat.cols(); x++) { int diffX = x - mouseX; // 不要取绝对值 int diffY = y - mouseY; // 不要取绝对值 double dist = Math.sqrt(diffX * diffX + diffY * diffY); // 距离 if (dist < radius) { // 在边界范围内的 int newX = (int) (dist * diffX / radius + mouseX); int newY = (int) (dist * diffY / radius + mouseY); double[] newPixel = srcMat.get(newY, newX); if (null != newPixel) { dstMat.put(y, x, newPixel); } } } } setIcon(dstMat); } private void extrudePic() { // https://blog.csdn.net/cbacq/article/details/17782895 Mat dstMat = srcMat.clone(); for (int y = 0; y < srcMat.rows(); y++) { for (int x = 0; x < srcMat.cols(); x++) { int diffX = x - mouseX; // 不要取绝对值 int diffY = y - mouseY; // 不要取绝对值 double dist = Math.sqrt(diffX * diffX + diffY * diffY); // 距离 if (dist < radius) { // 在边界范围内的 int newR = (int) (Math.sqrt(dist) * divisor); double theta = Math.atan2((double) diffY, (double) diffX);// 像素 到 点击位置 的连线的弧度 int newX = mouseX + (int) (newR * Math.cos(theta)); int newY = mouseY + (int) (newR * Math.sin(theta)); if (newX < 0) newX = 0; else if (newX >= srcMat.rows()) newX = srcMat.rows() - 1; if (newY < 0) newY = 0; else if (newY >= srcMat.cols()) newY = srcMat.cols() - 1; double[] newPixel = srcMat.get(newY, newX); if (null != newPixel) { dstMat.put(y, x, newPixel); } } } } setIcon(dstMat); } private void setIcon(Mat mat) { BufferedImage image = matToBufferedImage(mat); imageView.setIcon(new ImageIcon(image)); } private BufferedImage matToBufferedImage(Mat mat) { int cols = mat.cols(); int rows = mat.rows(); int elemSize = (int) mat.elemSize(); byte[] data = new byte[cols * rows * elemSize]; int type = BufferedImage.TYPE_BYTE_GRAY; mat.get(0, 0, data); if (3 == mat.channels()) { type = BufferedImage.TYPE_3BYTE_BGR; byte b; for (int i = 0; i < data.length; i = i + 3) { // opencv加载图片像素存在mat中的格式bgr 转为 rgb b = data[i]; data[i] = data[i + 2]; data[i + 2] = b; } } BufferedImage image = new BufferedImage(cols, rows, type); image.getRaster().setDataElements(0, 0, cols, rows, data); return image; } } |
一段python的参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 白天照手电筒效果 strength = 100 dst = np.zeros((rows, clols, 3), dtype="uint8") for i in range(rows): for j in range(cols): dist = math.pow((mouseY - j), 2) + math.pow((mouseX - i), 2)) distance = math.sqrt(dist) b = img[i,j][0] g = img[i,j][1] r = img[i,j][2] if (distance < radius): result = strength * radius b = b + result g = g + result r = r + result b = min(255, max(0, b)) g = min(255, max(0, g)) r = min(255, max(0, r)) dst[i, j] = np.uint8((b,g,r)) cv.imshow('',np.vstack((img, dst))) |
- end
声明
本文由崔维友 威格灵 cuiweiyou vigiles cuiweiyou 原创,转载请注明出处:http://www.gaohaiyan.com/3347.html
承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设