1 package org.opencv.test; 2 3 import java.io.BufferedReader; 4 import java.io.File; 5 import java.io.FileOutputStream; 6 import java.io.FileReader; 7 import java.io.IOException; 8 import java.nio.channels.FileChannel; 9 import java.nio.charset.Charset; 10 import java.util.List; 11 12 import junit.framework.TestCase; 13 14 import org.opencv.core.Core; 15 import org.opencv.core.CvType; 16 import org.opencv.core.Mat; 17 import org.opencv.core.Point; 18 import org.opencv.core.Point3; 19 import org.opencv.core.Rect; 20 import org.opencv.core.Scalar; 21 import org.opencv.core.Size; 22 import org.opencv.core.DMatch; 23 import org.opencv.core.KeyPoint; 24 import org.opencv.imgcodecs.Imgcodecs; 25 26 import android.util.Log; 27 28 public class OpenCVTestCase extends TestCase { 29 //change to 'true' to unblock fail on fail("Not yet implemented") 30 public static final boolean passNYI = true; 31 32 protected static boolean isTestCaseEnabled = true; 33 34 protected static final int matSize = 10; 35 protected static final double EPS = 0.001; 36 protected static final double weakEPS = 0.5; 37 38 private static final String TAG = "OpenCVTestCase"; 39 40 protected Mat dst; 41 protected Mat truth; 42 43 protected Scalar colorBlack; 44 protected Scalar colorWhite; 45 46 // Naming notation: <channels info>_[depth]_[dimensions]_value 47 // examples: gray0 - single channel 8U 2d Mat filled with 0 48 // grayRnd - single channel 8U 2d Mat filled with random numbers 49 // gray0_32f_1d 50 51 // TODO: OpenCVTestCase refactorings 52 // - rename matrices 53 // - create methods gray0() and create src1 explicitly 54 // - create some masks 55 // - use truth member everywhere - remove truth from base class - each test 56 // fixture should use own truth filed 57 58 protected Mat gray0; 59 protected Mat gray1; 60 protected Mat gray2; 61 protected Mat gray3; 62 protected Mat gray9; 63 protected Mat gray127; 64 protected Mat gray128; 65 protected Mat gray255; 66 protected Mat grayRnd; 67 68 protected Mat gray_16u_256; 69 protected Mat gray_16s_1024; 70 71 protected Mat gray0_32f; 72 protected Mat gray1_32f; 73 protected Mat gray3_32f; 74 protected Mat gray9_32f; 75 protected Mat gray255_32f; 76 protected Mat grayE_32f; 77 protected Mat grayRnd_32f; 78 79 protected Mat gray0_32f_1d; 80 81 protected Mat gray0_64f; 82 protected Mat gray0_64f_1d; 83 84 protected Mat rgba0; 85 protected Mat rgba128; 86 87 protected Mat rgbLena; 88 protected Mat grayChess; 89 90 protected Mat v1; 91 protected Mat v2; 92 93 @Override 94 protected void setUp() throws Exception { 95 super.setUp(); 96 97 dst = new Mat(); 98 assertTrue(dst.empty()); 99 truth = null; 100 101 colorBlack = new Scalar(0); 102 colorWhite = new Scalar(255, 255, 255); 103 104 gray0 = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(0)); 105 gray1 = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(1)); 106 gray2 = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(2)); 107 gray3 = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(3)); 108 gray9 = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(9)); 109 gray127 = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(127)); 110 gray128 = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(128)); 111 gray255 = new Mat(matSize, matSize, CvType.CV_8U, new Scalar(255)); 112 113 grayRnd = new Mat(matSize, matSize, CvType.CV_8U); 114 Core.randu(grayRnd, 0, 256); 115 116 gray_16u_256 = new Mat(matSize, matSize, CvType.CV_16U, new Scalar(256)); 117 gray_16s_1024 = new Mat(matSize, matSize, CvType.CV_16S, new Scalar(1024)); 118 119 gray0_32f = new Mat(matSize, matSize, CvType.CV_32F, new Scalar(0.0)); 120 gray1_32f = new Mat(matSize, matSize, CvType.CV_32F, new Scalar(1.0)); 121 gray3_32f = new Mat(matSize, matSize, CvType.CV_32F, new Scalar(3.0)); 122 gray9_32f = new Mat(matSize, matSize, CvType.CV_32F, new Scalar(9.0)); 123 gray255_32f = new Mat(matSize, matSize, CvType.CV_32F, new Scalar(255.0)); 124 grayE_32f = new Mat(matSize, matSize, CvType.CV_32F); 125 grayE_32f = Mat.eye(matSize, matSize, CvType.CV_32FC1); 126 grayRnd_32f = new Mat(matSize, matSize, CvType.CV_32F); 127 Core.randu(grayRnd_32f, 0, 256); 128 129 gray0_64f = new Mat(matSize, matSize, CvType.CV_64F, new Scalar(0.0)); 130 131 gray0_32f_1d = new Mat(1, matSize, CvType.CV_32F, new Scalar(0.0)); 132 gray0_64f_1d = new Mat(1, matSize, CvType.CV_64F, new Scalar(0.0)); 133 134 rgba0 = new Mat(matSize, matSize, CvType.CV_8UC4, Scalar.all(0)); 135 rgba128 = new Mat(matSize, matSize, CvType.CV_8UC4, Scalar.all(128)); 136 137 rgbLena = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH); 138 grayChess = Imgcodecs.imread(OpenCVTestRunner.CHESS_PATH, 0); 139 140 v1 = new Mat(1, 3, CvType.CV_32F); 141 v1.put(0, 0, 1.0, 3.0, 2.0); 142 v2 = new Mat(1, 3, CvType.CV_32F); 143 v2.put(0, 0, 2.0, 1.0, 3.0); 144 } 145 146 @Override 147 protected void tearDown() throws Exception { 148 149 gray0.release(); 150 gray1.release(); 151 gray2.release(); 152 gray3.release(); 153 gray9.release(); 154 gray127.release(); 155 gray128.release(); 156 gray255.release(); 157 gray_16u_256.release(); 158 gray_16s_1024.release(); 159 grayRnd.release(); 160 gray0_32f.release(); 161 gray1_32f.release(); 162 gray3_32f.release(); 163 gray9_32f.release(); 164 gray255_32f.release(); 165 grayE_32f.release(); 166 grayE_32f.release(); 167 grayRnd_32f.release(); 168 gray0_32f_1d.release(); 169 gray0_64f.release(); 170 gray0_64f_1d.release(); 171 rgba0.release(); 172 rgba128.release(); 173 rgbLena.release(); 174 grayChess.release(); 175 v1.release(); 176 v2.release(); 177 178 super.tearDown(); 179 } 180 181 @Override 182 protected void runTest() throws Throwable { 183 // Do nothing if the precondition does not hold. 184 if (isTestCaseEnabled) { 185 super.runTest(); 186 } else { 187 Log.e(TAG, "Test case \"" + this.getClass().getName() + "\" disabled!"); 188 } 189 } 190 191 protected Mat getMat(int type, double... vals) 192 { 193 return new Mat(matSize, matSize, type, new Scalar(vals)); 194 } 195 196 protected Mat makeMask(Mat m, double... vals) 197 { 198 m.submat(0, m.rows(), 0, m.cols() / 2).setTo(new Scalar(vals)); 199 return m; 200 } 201 202 public static void fail(String msg) { 203 if(msg == "Not yet implemented" && passNYI) 204 return; 205 TestCase.fail(msg); 206 } 207 208 public static <E extends Number> void assertListEquals(List<E> list1, List<E> list2) { 209 if (list1.size() != list2.size()) { 210 throw new UnsupportedOperationException(); 211 } 212 213 if (!list1.isEmpty()) 214 { 215 if (list1.get(0) instanceof Float || list1.get(0) instanceof Double) 216 throw new UnsupportedOperationException(); 217 } 218 219 for (int i = 0; i < list1.size(); i++) 220 assertEquals(list1.get(i), list2.get(i)); 221 } 222 223 public static <E extends Number> void assertListEquals(List<E> list1, List<E> list2, double epsilon) { 224 if (list1.size() != list2.size()) { 225 throw new UnsupportedOperationException(); 226 } 227 228 for (int i = 0; i < list1.size(); i++) 229 assertTrue(Math.abs(list1.get(i).doubleValue() - list2.get(i).doubleValue()) <= epsilon); 230 } 231 232 public static <E extends Number> void assertArrayEquals(E[] ar1, E[] ar2, double epsilon) { 233 if (ar1.length != ar2.length) { 234 fail("Arrays have different sizes."); 235 } 236 237 for (int i = 0; i < ar1.length; i++) 238 assertEquals(ar1[i].doubleValue(), ar2[i].doubleValue(), epsilon); 239 //assertTrue(Math.abs(ar1[i].doubleValue() - ar2[i].doubleValue()) <= epsilon); 240 } 241 242 public static void assertArrayEquals(double[] ar1, double[] ar2, double epsilon) { 243 if (ar1.length != ar2.length) { 244 fail("Arrays have different sizes."); 245 } 246 247 for (int i = 0; i < ar1.length; i++) 248 assertEquals(ar1[i], ar2[i], epsilon); 249 //assertTrue(Math.abs(ar1[i].doubleValue() - ar2[i].doubleValue()) <= epsilon); 250 } 251 252 public static void assertListMatEquals(List<Mat> list1, List<Mat> list2, double epsilon) { 253 if (list1.size() != list2.size()) { 254 throw new UnsupportedOperationException(); 255 } 256 257 for (int i = 0; i < list1.size(); i++) 258 assertMatEqual(list1.get(i), list2.get(i), epsilon); 259 } 260 261 public static void assertListPointEquals(List<Point> list1, List<Point> list2, double epsilon) { 262 if (list1.size() != list2.size()) { 263 throw new UnsupportedOperationException(); 264 } 265 266 for (int i = 0; i < list1.size(); i++) 267 assertPointEquals(list1.get(i), list2.get(i), epsilon); 268 } 269 270 public static void assertArrayPointsEquals(Point[] vp1, Point[] vp2, double epsilon) { 271 if (vp1.length != vp2.length) { 272 fail("Arrays have different sizes."); 273 } 274 275 for (int i = 0; i < vp1.length; i++) 276 assertPointEquals(vp1[i], vp2[i], epsilon); 277 } 278 public static void assertListPoint3Equals(List<Point3> list1, List<Point3> list2, double epsilon) { 279 if (list1.size() != list2.size()) { 280 throw new UnsupportedOperationException(); 281 } 282 283 for (int i = 0; i < list1.size(); i++) 284 assertPoint3Equals(list1.get(i), list2.get(i), epsilon); 285 } 286 287 public static void assertListRectEquals(List<Rect> list1, List<Rect> list2) { 288 if (list1.size() != list2.size()) { 289 throw new UnsupportedOperationException(); 290 } 291 292 for (int i = 0; i < list1.size(); i++) 293 assertRectEquals(list1.get(i), list2.get(i)); 294 } 295 296 public static void assertRectEquals(Rect expected, Rect actual) { 297 String msg = "expected:<" + expected + "> but was:<" + actual + ">"; 298 assertEquals(msg, expected.x, actual.x); 299 assertEquals(msg, expected.y, actual.y); 300 assertEquals(msg, expected.width, actual.width); 301 assertEquals(msg, expected.height, actual.height); 302 } 303 304 public static void assertMatEqual(Mat m1, Mat m2) { 305 compareMats(m1, m2, true); 306 } 307 308 public static void assertMatNotEqual(Mat m1, Mat m2) { 309 compareMats(m1, m2, false); 310 } 311 312 public static void assertMatEqual(Mat expected, Mat actual, double eps) { 313 compareMats(expected, actual, eps, true); 314 } 315 316 public static void assertMatNotEqual(Mat expected, Mat actual, double eps) { 317 compareMats(expected, actual, eps, false); 318 } 319 320 public static void assertKeyPointEqual(KeyPoint expected, KeyPoint actual, double eps) { 321 String msg = "expected:<" + expected + "> but was:<" + actual + ">"; 322 assertTrue(msg, Math.hypot(expected.pt.x - actual.pt.x, expected.pt.y - actual.pt.y) < eps); 323 assertTrue(msg, Math.abs(expected.size - actual.size) < eps); 324 assertTrue(msg, Math.abs(expected.angle - actual.angle) < eps); 325 assertTrue(msg, Math.abs(expected.response - actual.response) < eps); 326 assertEquals(msg, expected.octave, actual.octave); 327 assertEquals(msg, expected.class_id, actual.class_id); 328 } 329 330 public static void assertListKeyPointEquals(List<KeyPoint> expected, List<KeyPoint> actual, double epsilon) { 331 assertEquals(expected.size(), actual.size()); 332 for (int i = 0; i < expected.size(); i++) 333 assertKeyPointEqual(expected.get(i), actual.get(i), epsilon); 334 } 335 336 public static void assertDMatchEqual(DMatch expected, DMatch actual, double eps) { 337 String msg = "expected:<" + expected + "> but was:<" + actual + ">"; 338 assertEquals(msg, expected.queryIdx, actual.queryIdx); 339 assertEquals(msg, expected.trainIdx, actual.trainIdx); 340 assertEquals(msg, expected.imgIdx, actual.imgIdx); 341 assertTrue(msg, Math.abs(expected.distance - actual.distance) < eps); 342 } 343 344 public static void assertScalarEqual(Scalar expected, Scalar actual, double eps) { 345 String msg = "expected:<" + expected + "> but was:<" + actual + ">"; 346 assertTrue(msg, Math.abs(expected.val[0] - actual.val[0]) < eps); 347 assertTrue(msg, Math.abs(expected.val[1] - actual.val[1]) < eps); 348 assertTrue(msg, Math.abs(expected.val[2] - actual.val[2]) < eps); 349 assertTrue(msg, Math.abs(expected.val[3] - actual.val[3]) < eps); 350 } 351 352 public static void assertArrayDMatchEquals(DMatch[] expected, DMatch[] actual, double epsilon) { 353 assertEquals(expected.length, actual.length); 354 for (int i = 0; i < expected.length; i++) 355 assertDMatchEqual(expected[i], actual[i], epsilon); 356 } 357 358 public static void assertListDMatchEquals(List<DMatch> expected, List<DMatch> actual, double epsilon) { 359 DMatch expectedArray[] = expected.toArray(new DMatch[0]); 360 DMatch actualArray[] = actual.toArray(new DMatch[0]); 361 assertArrayDMatchEquals(expectedArray, actualArray, epsilon); 362 } 363 364 public static void assertPointEquals(Point expected, Point actual, double eps) { 365 String msg = "expected:<" + expected + "> but was:<" + actual + ">"; 366 assertEquals(msg, expected.x, actual.x, eps); 367 assertEquals(msg, expected.y, actual.y, eps); 368 } 369 370 public static void assertSizeEquals(Size expected, Size actual, double eps) { 371 String msg = "expected:<" + expected + "> but was:<" + actual + ">"; 372 assertEquals(msg, expected.width, actual.width, eps); 373 assertEquals(msg, expected.height, actual.height, eps); 374 } 375 376 public static void assertPoint3Equals(Point3 expected, Point3 actual, double eps) { 377 String msg = "expected:<" + expected + "> but was:<" + actual + ">"; 378 assertEquals(msg, expected.x, actual.x, eps); 379 assertEquals(msg, expected.y, actual.y, eps); 380 assertEquals(msg, expected.z, actual.z, eps); 381 } 382 383 static private void compareMats(Mat expected, Mat actual, boolean isEqualityMeasured) { 384 if (expected.type() != actual.type() || expected.cols() != actual.cols() || expected.rows() != actual.rows()) { 385 throw new UnsupportedOperationException("Can not compare " + expected + " and " + actual); 386 } 387 388 if (expected.depth() == CvType.CV_32F || expected.depth() == CvType.CV_64F) { 389 if (isEqualityMeasured) 390 throw new UnsupportedOperationException( 391 "Floating-point Mats must not be checked for exact match. Use assertMatEqual(Mat expected, Mat actual, double eps) instead."); 392 else 393 throw new UnsupportedOperationException( 394 "Floating-point Mats must not be checked for exact match. Use assertMatNotEqual(Mat expected, Mat actual, double eps) instead."); 395 } 396 397 Mat diff = new Mat(); 398 Core.absdiff(expected, actual, diff); 399 Mat reshaped = diff.reshape(1); 400 int mistakes = Core.countNonZero(reshaped); 401 402 reshaped.release(); 403 diff.release(); 404 405 if (isEqualityMeasured) 406 assertTrue("Mats are different in " + mistakes + " points", 0 == mistakes); 407 else 408 assertFalse("Mats are equal", 0 == mistakes); 409 } 410 411 static private void compareMats(Mat expected, Mat actual, double eps, boolean isEqualityMeasured) { 412 if (expected.type() != actual.type() || expected.cols() != actual.cols() || expected.rows() != actual.rows()) { 413 throw new UnsupportedOperationException("Can not compare " + expected + " and " + actual); 414 } 415 416 Mat diff = new Mat(); 417 Core.absdiff(expected, actual, diff); 418 double maxDiff = Core.norm(diff, Core.NORM_INF); 419 420 if (isEqualityMeasured) 421 assertTrue("Max difference between expected and actiual Mats is "+ maxDiff + ", that bigger than " + eps, 422 Core.checkRange(diff, true, 0.0, eps)); 423 else 424 assertFalse("Max difference between expected and actiual Mats is "+ maxDiff + ", that less than " + eps, 425 Core.checkRange(diff, true, 0.0, eps)); 426 } 427 428 protected static String readFile(String path) { 429 try { 430 BufferedReader br = new BufferedReader(new FileReader(path)); 431 String line; 432 StringBuffer result = new StringBuffer(); 433 while ((line = br.readLine()) != null) { 434 result.append(line); 435 result.append("\n"); 436 } 437 return result.toString(); 438 } catch (IOException e) { 439 OpenCVTestRunner.Log("Failed to read file \"" + path 440 + "\". Exception is thrown: " + e); 441 return null; 442 } 443 } 444 445 protected static void writeFile(String path, String content) { 446 FileOutputStream stream = null; 447 try { 448 stream = new FileOutputStream(new File(path)); 449 FileChannel fc = stream.getChannel(); 450 fc.write(Charset.defaultCharset().encode(content)); 451 } catch (IOException e) { 452 OpenCVTestRunner.Log("Failed to write file \"" + path 453 + "\". Exception is thrown: " + e); 454 } finally { 455 if (stream != null) 456 try { 457 stream.close(); 458 } catch (IOException e) { 459 OpenCVTestRunner.Log("Exception is thrown: " + e); 460 } 461 } 462 } 463 464 } 465