From 9907cc8c67f359740f27cac5dc98a8b6cae20bab Mon Sep 17 00:00:00 2001 From: Mattia Astorino Date: Mon, 7 May 2018 16:23:17 +0200 Subject: [PATCH] Develop (#185) * chore: Update meta and readme * chore. Update README * Refactor/linting - tslint-xo (#178) * refactor(deps): added tslint, cleanup, and activationEvents modified * refactor(lint): linting... * refactor(changelog): changelo method refactor (should be tested) * refactor(theme-icons): linting and small refactor * refactor(accents-setter): linting and small refactor * chore(travis): added travis file * fix(Lighter): Fix folders icon association * chore: Clean test files * fix(Icons): Add icon to .spec.ts files * chore: Update git icon * Update issue templates (#184) --- .github/ISSUE_TEMPLATE/Bug_report.md | 35 + .github/ISSUE_TEMPLATE/Custom.md | 7 + .github/ISSUE_TEMPLATE/Feature_request.md | 17 + .gulp/consts/log.ts | 2 +- .gulp/interfaces/itheme-icons-accents.ts | 6 +- .gulp/interfaces/itheme-icons-item.ts | 2 +- .gulp/interfaces/itheme-icons-variants.ts | 28 +- .gulp/tasks/changelog-title.ts | 9 +- .gulp/tasks/icons-accents.ts | 60 +- .gulp/tasks/icons-variants.ts | 57 +- .gulp/tasks/icons.ts | 48 +- .gulp/tasks/themes.ts | 33 +- .gulp/tasks/watcher.ts | 10 +- .travis.yml | 6 + .vscode/settings.json | 1 + README.md | 5 +- extensions/commands/accents-setter/index.ts | 111 +- extensions/commands/theme-icons/index.ts | 105 +- extensions/consts/files.ts | 3 +- extensions/consts/paths.ts | 2 +- extensions/helpers/changelog.ts | 84 +- extensions/helpers/fs.ts | 66 +- extensions/helpers/settings.ts | 31 +- extensions/helpers/vscode.ts | 27 +- .../interfaces/iaccent-custom-property.ts | 2 +- extensions/interfaces/idefaults.ts | 32 +- extensions/interfaces/igeneric-object.ts | 2 +- extensions/interfaces/ipackage.json.ts | 48 +- extensions/interfaces/ipaths.ts | 12 +- .../interfaces/itheme-custom-properties.ts | 2 +- extensions/interfaces/itheme-icons.ts | 1013 +++++------ extensions/material.theme.config.ts | 9 +- gulpfile.babel.ts | 2 +- package.json | 15 +- src/icons/partials/fileExtensions.js | 1 + src/icons/svgs/git.svg | 2 +- src/themes/theme-template-color-theme.json | 2 + test/source.c | 1513 ----------------- test/source.c++ | 1413 +-------------- test/source.cc | 1513 ----------------- tsconfig.json | 2 +- tslint.json | 7 + yarn.lock | 479 ++---- 43 files changed, 1075 insertions(+), 5749 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/Bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/Custom.md create mode 100644 .github/ISSUE_TEMPLATE/Feature_request.md create mode 100644 .travis.yml create mode 100644 tslint.json diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md new file mode 100644 index 0000000..4de26c7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -0,0 +1,35 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/Custom.md b/.github/ISSUE_TEMPLATE/Custom.md new file mode 100644 index 0000000..18074d2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Custom.md @@ -0,0 +1,7 @@ +--- +name: General +about: Give us your feedback about this extension + +--- + + diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md new file mode 100644 index 0000000..5384295 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gulp/consts/log.ts b/.gulp/consts/log.ts index bc933ba..94dba4d 100644 --- a/.gulp/consts/log.ts +++ b/.gulp/consts/log.ts @@ -4,4 +4,4 @@ export const MESSAGE_BUMP_SUCCESS: string = ' Finished successfully\n'; export const MESSAGE_ICON_ERROR: string = 'There is an error with JSON generated for icons'; export const MESSAGE_ICON_ACCENTS_ERROR: string = 'Failed to create accents icon themes, please read the log file.'; export const MESSAGE_GENERATED: string = 'Generated'; -export const MESSAGE_THEME_VARIANT_PARSE_ERROR: string = 'Error when parsing json for theme variants'; \ No newline at end of file +export const MESSAGE_THEME_VARIANT_PARSE_ERROR: string = 'Error when parsing json for theme variants'; diff --git a/.gulp/interfaces/itheme-icons-accents.ts b/.gulp/interfaces/itheme-icons-accents.ts index e2a5324..8f60ca1 100644 --- a/.gulp/interfaces/itheme-icons-accents.ts +++ b/.gulp/interfaces/itheme-icons-accents.ts @@ -1,8 +1,8 @@ -import { IThemeIconsItem } from "./itheme-icons-item"; +import {IThemeIconsItem} from './itheme-icons-item'; export interface IThemeIconsAccents { iconDefinitions: { _folder_open: IThemeIconsItem; _folder_open_build: IThemeIconsItem; - } -} \ No newline at end of file + }; +} diff --git a/.gulp/interfaces/itheme-icons-item.ts b/.gulp/interfaces/itheme-icons-item.ts index 1a5c615..964462c 100644 --- a/.gulp/interfaces/itheme-icons-item.ts +++ b/.gulp/interfaces/itheme-icons-item.ts @@ -1,3 +1,3 @@ export interface IThemeIconsItem { iconPath: string; -} \ No newline at end of file +} diff --git a/.gulp/interfaces/itheme-icons-variants.ts b/.gulp/interfaces/itheme-icons-variants.ts index 15e91e7..93c2bfb 100644 --- a/.gulp/interfaces/itheme-icons-variants.ts +++ b/.gulp/interfaces/itheme-icons-variants.ts @@ -1,17 +1,17 @@ -import { IThemeIconsItem } from "./itheme-icons-item"; +import {IThemeIconsItem} from './itheme-icons-item'; export interface IThemeIconsVariants { iconDefinitions: { - "_folder_dark": IThemeIconsItem; - "_folder_dark_build": IThemeIconsItem; - "_folder_light": IThemeIconsItem; - "_folder_light_build": IThemeIconsItem; - "_folder_vscode": IThemeIconsItem; - "_folder_gulp": IThemeIconsItem; - "_folder_node": IThemeIconsItem; - "_folder_images": IThemeIconsItem; - "_folder_js": IThemeIconsItem; - "_folder_src": IThemeIconsItem; - "_folder_assets": IThemeIconsItem; - } -} \ No newline at end of file + _folder_dark: IThemeIconsItem; + _folder_dark_build: IThemeIconsItem; + _folder_light: IThemeIconsItem; + _folder_light_build: IThemeIconsItem; + _folder_vscode: IThemeIconsItem; + _folder_gulp: IThemeIconsItem; + _folder_node: IThemeIconsItem; + _folder_images: IThemeIconsItem; + _folder_js: IThemeIconsItem; + _folder_src: IThemeIconsItem; + _folder_assets: IThemeIconsItem; + }; +} diff --git a/.gulp/tasks/changelog-title.ts b/.gulp/tasks/changelog-title.ts index c892c40..e8da38a 100644 --- a/.gulp/tasks/changelog-title.ts +++ b/.gulp/tasks/changelog-title.ts @@ -1,11 +1,10 @@ -import * as gulp from "gulp"; import * as fs from 'fs'; -import { CHARSET } from "../../extensions/consts/files"; - +import * as gulp from 'gulp'; +import {CHARSET} from './../../extensions/consts/files'; export default gulp.task('changelog-title', () => { fs.writeFileSync( './CHANGELOG.md', fs.readFileSync('CHANGELOG.md', CHARSET).replace('# Change Log', '# Material Theme Changelog'), - { encoding: CHARSET }); -}); \ No newline at end of file + {encoding: CHARSET}); +}); diff --git a/.gulp/tasks/icons-accents.ts b/.gulp/tasks/icons-accents.ts index a643185..f0b6466 100644 --- a/.gulp/tasks/icons-accents.ts +++ b/.gulp/tasks/icons-accents.ts @@ -3,22 +3,19 @@ import * as gulp from 'gulp'; import * as gutil from 'gulp-util'; import * as path from 'path'; -import { MESSAGE_GENERATED, MESSAGE_ICON_ACCENTS_ERROR } from "../consts/log"; +import {MESSAGE_GENERATED, MESSAGE_ICON_ACCENTS_ERROR} from './../consts/log'; -import { CHARSET } from "../../extensions/consts/files"; -import { IDefaults } from "../../extensions/interfaces/idefaults"; -import { IThemeIconsAccents } from "../interfaces/itheme-icons-accents"; -import PATHS from '../../extensions/consts/paths' -import { IThemeIconsItem } from '../interfaces/itheme-icons-item'; -import { getAccentableIcons } from '../../extensions/helpers/fs'; +import {CHARSET} from './../../extensions/consts/files'; +import {IThemeIconsAccents} from './../interfaces/itheme-icons-accents'; +import PATHS from './../../extensions/consts/paths'; +import {IThemeIconsItem} from './../interfaces/itheme-icons-item'; +import {getAccentableIcons, getDefaultValues} from './../../extensions/helpers/fs'; const BASE_ICON_THEME_PATH: string = path.join(process.cwd(), PATHS.THEMES, './Material-Theme-Icons.json'); -const DEFAULTS: IDefaults = require('../../extensions/defaults.json'); +const DEFAULTS = getDefaultValues(); /** * Normalizes icon path - * @param {string} iconPath - * @returns {string} */ function normalizeIconPath(iconPath: string): string { return path.join(process.cwd(), PATHS.ICONS, iconPath); @@ -26,9 +23,6 @@ function normalizeIconPath(iconPath: string): string { /** * Replaces a file name with the accented filename - * @param {string} name - * @param {string} accentName - * @returns {string} */ function replaceNameWithAccent(name: string, accentName: string): string { return name.replace('.svg', `.accent.${ accentName }.svg`); @@ -36,24 +30,17 @@ function replaceNameWithAccent(name: string, accentName: string): string { /** * Replaces a SVG colour - * - * @param {string} filecontent - * @param {string} colour - * @returns {string} */ export function replaceSVGColour(filecontent: string, colour: string): string { return filecontent.replace(new RegExp('#(80CBC4)', 'i'), ($0, $1) => { - - colour = colour.replace('#', ''); - console.log(`Replacing colour ${ $1 } with ${ colour }`) - return $0.replace($1, colour); + const newColour = colour.replace('#', ''); + console.log(`Replacing colour ${ $1 } with ${ newColour }`); + return $0.replace($1, newColour); }); } /** * Replaces white spaces in accents' names - * @param {string} input - * @returns {string} */ function replaceWhiteSpaces(input: string): string { return input.replace(/\s+/g, '-'); @@ -61,18 +48,15 @@ function replaceWhiteSpaces(input: string): string { /** * Writes a new svg file - * @param {string} fromFile - * @param {string} toFile - * @param {string} accentColour */ function writeSVGIcon(fromFile: string, toFile: string, accent: string): void { - let fileContent: string = fs.readFileSync(normalizeIconPath(fromFile), CHARSET); - let content: string = replaceSVGColour(fileContent, DEFAULTS.accents[accent]); - toFile = normalizeIconPath(toFile); + const fileContent: string = fs.readFileSync(normalizeIconPath(fromFile), CHARSET); + const content: string = replaceSVGColour(fileContent, DEFAULTS.accents[accent]); + const pathToFile = normalizeIconPath(toFile); - gutil.log(gutil.colors.gray(`Accented icon ${toFile} created with colour ${ accent } (${ DEFAULTS.accents[accent] })`)); + gutil.log(gutil.colors.gray(`Accented icon ${pathToFile} created with colour ${ accent } (${ DEFAULTS.accents[accent] })`)); - fs.writeFileSync(toFile, content); + fs.writeFileSync(pathToFile, content); } // Exports task to index.ts @@ -83,21 +67,21 @@ export default gulp.task('build:icons.accents', cb => { basetheme = require(BASE_ICON_THEME_PATH); Object.keys(DEFAULTS.accents).forEach(key => { - let iconName = replaceWhiteSpaces(key); - let themecopy: IThemeIconsAccents = JSON.parse(JSON.stringify(basetheme)); - let themePath: string = path.join(PATHS.THEMES, `./Material-Theme-Icons-${ key }.json`); + const iconName = replaceWhiteSpaces(key); + const themecopy: IThemeIconsAccents = JSON.parse(JSON.stringify(basetheme)); + const themePath: string = path.join(PATHS.THEMES, `./Material-Theme-Icons-${ key }.json`); getAccentableIcons().forEach(accentableIconName => { gutil.log(gutil.colors.gray(`Preparing ${ accentableIconName } accented icon`)); - let iconOriginDefinition: IThemeIconsItem = (basetheme.iconDefinitions as any)[accentableIconName]; - let iconCopyDefinition: IThemeIconsItem = (themecopy.iconDefinitions as any)[accentableIconName]; + const iconOriginDefinition: IThemeIconsItem = (basetheme.iconDefinitions as any)[accentableIconName]; + const iconCopyDefinition: IThemeIconsItem = (themecopy.iconDefinitions as any)[accentableIconName]; if (iconOriginDefinition !== undefined && typeof iconOriginDefinition.iconPath === 'string' && iconCopyDefinition !== undefined && typeof iconCopyDefinition.iconPath === 'string') { iconCopyDefinition.iconPath = replaceNameWithAccent(iconOriginDefinition.iconPath, iconName); writeSVGIcon(iconOriginDefinition.iconPath, iconCopyDefinition.iconPath, key); } else { - gutil.log(gutil.colors.yellow(`Icon ${ accentableIconName } not found`)) + gutil.log(gutil.colors.yellow(`Icon ${ accentableIconName } not found`)); } }); @@ -124,4 +108,4 @@ export default gulp.task('build:icons.accents', cb => { } cb(); -}); \ No newline at end of file +}); diff --git a/.gulp/tasks/icons-variants.ts b/.gulp/tasks/icons-variants.ts index c95f049..6c0232c 100644 --- a/.gulp/tasks/icons-variants.ts +++ b/.gulp/tasks/icons-variants.ts @@ -1,44 +1,47 @@ -import {getVariantIcons} from '../../extensions/helpers/fs'; import * as gulp from 'gulp'; import * as path from 'path'; import * as fs from 'fs'; -import { CHARSET } from "../../extensions/consts/files"; -import { IPackageJSON } from "../../extensions/interfaces/ipackage.json"; -import { IThemeIconsVariants } from "../interfaces/itheme-icons-variants"; -import PATHS from '../../extensions/consts/paths' -import { getDefaultValues } from "../../extensions/helpers/fs"; -import { IDefaultsThemeVariantColours } from "../../extensions/interfaces/idefaults"; -import { IThemeIconsItem } from '../interfaces/itheme-icons-item'; +import {IThemeIconsVariants} from '../interfaces/itheme-icons-variants'; +import {CHARSET} from './../../extensions/consts/files'; +import PATHS from './../../extensions/consts/paths'; +import {getDefaultValues, getVariantIcons, getPackageJSON} from './../../extensions/helpers/fs'; +import {IDefaultsThemeVariant} from './../../extensions/interfaces/idefaults'; +import {IThemeIconsItem} from './../interfaces/itheme-icons-item'; -const PACKAGE_JSON: IPackageJSON = require(path.join(process.cwd(), './package.json')); +const PACKAGE_JSON = getPackageJSON(); -let variants: IDefaultsThemeVariantColours = getDefaultValues().themeVariantsColours; - -function writeIconVariant(filepath: string, destpath: string, colour: string): void { - let regexp = new RegExp('(#4a616c)', 'i') - filepath = path.join(process.cwd(), PATHS.ICONS, filepath); - destpath = path.join(process.cwd(), PATHS.ICONS, destpath); - fs.writeFileSync(destpath, fs.readFileSync(filepath, CHARSET).replace(regexp, ($0, $1) => $0.replace($1, colour)), { encoding: CHARSET }) ; -} +const variants: IDefaultsThemeVariant = getDefaultValues().themeVariantsColours; +const writeIconVariant = (filepath: string, destpath: string, colour: string): void => { + const regexp = new RegExp('(#4a616c)', 'i'); + const finalFilePath = path.join(process.cwd(), PATHS.ICONS, filepath); + const finalDestpath = path.join(process.cwd(), PATHS.ICONS, destpath); + fs.writeFileSync( + finalDestpath, + fs.readFileSync(finalFilePath, CHARSET) + .replace(regexp, ($0, $1) => $0.replace($1, colour)), {encoding: CHARSET} + ); +}; export default gulp.task('build:icons.variants', callback => { try { Object.keys(variants).forEach(variantName => { PACKAGE_JSON.contributes.iconThemes.forEach(contribute => { - let regexpCheck: RegExp = new RegExp(Object.keys(variants).join('|'), 'i'); + const regexpCheck: RegExp = new RegExp(Object.keys(variants).join('|'), 'i'); - if (regexpCheck.test(contribute.path) || regexpCheck.test(contribute.id)) return; + if (regexpCheck.test(contribute.path) || regexpCheck.test(contribute.id)) { + return; + } - let basepath: string = path.join(process.cwd(), contribute.path); - let basetheme: IThemeIconsVariants = require(basepath); - let theme: IThemeIconsVariants = JSON.parse(JSON.stringify(basetheme)); - let variant = variants[variantName]; + const basepath: string = path.join(process.cwd(), contribute.path); + const basetheme: IThemeIconsVariants = require(basepath); + const theme: IThemeIconsVariants = JSON.parse(JSON.stringify(basetheme)); + const variant = variants[variantName]; - getVariantIcons().forEach(_iconName => { - let basethemeIcon: IThemeIconsItem = (basetheme.iconDefinitions as any)[_iconName]; - let themeIcon: IThemeIconsItem = (theme.iconDefinitions as any)[_iconName]; + getVariantIcons().forEach(iconName => { + const basethemeIcon: IThemeIconsItem = (basetheme.iconDefinitions as any)[iconName]; + const themeIcon: IThemeIconsItem = (theme.iconDefinitions as any)[iconName]; if (themeIcon !== undefined) { themeIcon.iconPath = themeIcon.iconPath.replace('.svg', `${ variantName }.svg`); @@ -57,4 +60,4 @@ export default gulp.task('build:icons.variants', callback => { } callback(); -}); \ No newline at end of file +}); diff --git a/.gulp/tasks/icons.ts b/.gulp/tasks/icons.ts index da574b7..ae3d6e7 100644 --- a/.gulp/tasks/icons.ts +++ b/.gulp/tasks/icons.ts @@ -4,24 +4,22 @@ import * as gutil from 'gulp-util'; import * as mustache from 'mustache'; import * as path from 'path'; -import { HR, MESSAGE_GENERATED, MESSAGE_ICON_ERROR } from './../consts/log'; +import {HR, MESSAGE_GENERATED, MESSAGE_ICON_ERROR} from './../consts/log'; -import { CHARSET } from "../../extensions/consts/files"; -import { IGenericObject } from "../../extensions/interfaces/igeneric-object"; -import { IIcon } from './../interfaces/iicon'; -import paths from '../../extensions/consts/paths'; -import { ensureDir } from '../../extensions/helpers/fs'; +import {CHARSET} from './../../extensions/consts/files'; +import {IGenericObject} from './../../extensions/interfaces/igeneric-object'; +import {IIcon} from './../interfaces/iicon'; +import paths from './../../extensions/consts/paths'; +import {ensureDir} from './../../extensions/helpers/fs'; /** * Returns an object implementing the IIcon interface - * @param {string} fileName - * @returns {IIcon} */ -function iconFactory(fileName: string): IIcon { - gutil.log(gutil.colors.gray(`Processing icon ${ fileName }`)) +const iconFactory = (fileName: string): IIcon => { + gutil.log(gutil.colors.gray(`Processing icon ${ fileName }`)); let name: string = path.basename(fileName, path.extname(fileName)); - let filename: string = name; - let last: boolean = false; + const filename: string = name; + const last: boolean = false; // renaming icon for vscode // if the icon filename starts with a folder prefix, @@ -35,8 +33,8 @@ function iconFactory(fileName: string): IIcon { gutil.log(gutil.colors.gray(`VSCode icon name ${ name } with filename ${ filename }`)); - return { filename, name, last } as IIcon; -} + return {filename, name, last} as IIcon; +}; /** * > Build Icons @@ -44,24 +42,26 @@ function iconFactory(fileName: string): IIcon { */ export default gulp.task('build:icons', cb => { let contents: string; - let fileNames: string[] = fs.readdirSync(path.join(paths.SRC, `./icons/svgs`)); - let icons: IIcon[] = fileNames.map(fileName => iconFactory(fileName)); - let partials: string[] = fs.readdirSync(path.join(paths.SRC, `./icons/partials`)); - let partialsData: IGenericObject = {}; - let pathTemp: string = './themes/.material-theme-icons.tmp'; + const fileNames: string[] = fs.readdirSync(path.join(paths.SRC, './icons/svgs')); + const icons: IIcon[] = fileNames.map(fileName => iconFactory(fileName)); + const partials: string[] = fs.readdirSync(path.join(paths.SRC, './icons/partials')); + const partialsData: IGenericObject = {}; + const pathTemp: string = './themes/.material-theme-icons.tmp'; ensureDir(path.join(paths.THEMES)); icons[icons.length - 1].last = true; partials.forEach(partial => { - partialsData[path.basename(partial, path.extname(partial))] = fs.readFileSync(path.join(paths.SRC, `./icons/partials`, `./${partial}`), CHARSET); + partialsData[path.basename(partial, path.extname(partial))] = fs.readFileSync( + path.join(paths.SRC, './icons/partials', `./${partial}` + ), CHARSET); }); contents = mustache.render( - fs.readFileSync(path.join(paths.SRC, `./icons/icons-theme.json`), CHARSET) - , { icons } - , partialsData + fs.readFileSync(path.join(paths.SRC, './icons/icons-theme.json'), CHARSET), + {icons}, + partialsData ); try { @@ -72,7 +72,7 @@ export default gulp.task('build:icons', cb => { return; } - fs.writeFileSync(pathTemp, contents, { encoding: CHARSET }); + fs.writeFileSync(pathTemp, contents, {encoding: CHARSET}); gutil.log(gutil.colors.gray(HR)); gutil.log(MESSAGE_GENERATED, gutil.colors.green(pathTemp)); diff --git a/.gulp/tasks/themes.ts b/.gulp/tasks/themes.ts index 9dca1a8..693ef7c 100644 --- a/.gulp/tasks/themes.ts +++ b/.gulp/tasks/themes.ts @@ -4,25 +4,24 @@ import * as gulpUtil from 'gulp-util'; import * as mustache from 'mustache'; import * as path from 'path'; -import { HR, MESSAGE_GENERATED, MESSAGE_THEME_VARIANT_PARSE_ERROR } from './../consts/log'; +import {HR, MESSAGE_GENERATED, MESSAGE_THEME_VARIANT_PARSE_ERROR} from './../consts/log'; -import { CHARSET } from "../../extensions/consts/files"; -import { IDefaults } from "../../extensions/interfaces/idefaults"; -import { IThemeVariant } from './../interfaces/itheme-variant'; -import paths from '../../extensions/consts/paths'; -import { ensureDir } from '../../extensions/helpers/fs'; +import {CHARSET} from './../../extensions/consts/files'; +import {IThemeVariant} from './../interfaces/itheme-variant'; +import paths from './../../extensions/consts/paths'; +import {ensureDir, getDefaultValues} from './../../extensions/helpers/fs'; -let commons: IDefaults = require('../../extensions/defaults.json'); +const commons = getDefaultValues(); -let themeTemplateFileContent: string = fs.readFileSync(path.join(paths.SRC, `/themes/theme-template-color-theme.json`), CHARSET); -let themeVariants: IThemeVariant[] = []; +const themeTemplateFileContent: string = fs.readFileSync(path.join(paths.SRC, '/themes/theme-template-color-theme.json'), CHARSET); +const themeVariants: IThemeVariant[] = []; -let fileNames: string[] = fs.readdirSync(path.join(paths.SRC, `./themes/settings/specific`)); +const fileNames: string[] = fs.readdirSync(path.join(paths.SRC, './themes/settings/specific')); // build theme variants for later use in templating fileNames.forEach(fileName => { - let filePath: string = path.join(paths.SRC, `./themes/settings/specific`, `./${fileName}`); - let contents: string = fs.readFileSync(filePath, CHARSET); + const filePath: string = path.join(paths.SRC, './themes/settings/specific', `./${fileName}`); + const contents: string = fs.readFileSync(filePath, CHARSET); try { themeVariants.push(JSON.parse(contents)); @@ -42,12 +41,12 @@ export default gulp.task('build:themes', cb => { try { themeVariants.forEach(variant => { - let filePath = path.join(paths.THEMES, `./${variant.name}.json`); - let templateData = { commons, variant }; - let templateJSON: any = JSON.parse(mustache.render(themeTemplateFileContent, templateData)); - let templateJSONStringified: string = JSON.stringify(templateJSON, null, 2); + const filePath = path.join(paths.THEMES, `./${variant.name}.json`); + const templateData = {commons, variant}; + const templateJSON: any = JSON.parse(mustache.render(themeTemplateFileContent, templateData)); + const templateJSONStringified: string = JSON.stringify(templateJSON, null, 2); - fs.writeFileSync(filePath, templateJSONStringified, { encoding: CHARSET }); + fs.writeFileSync(filePath, templateJSONStringified, {encoding: CHARSET}); gulpUtil.log(MESSAGE_GENERATED, gulpUtil.colors.green(filePath)); }); diff --git a/.gulp/tasks/watcher.ts b/.gulp/tasks/watcher.ts index e0be4d1..cc2dddd 100644 --- a/.gulp/tasks/watcher.ts +++ b/.gulp/tasks/watcher.ts @@ -1,7 +1,7 @@ -import * as gulp from "gulp"; -import * as path from "path"; +import * as gulp from 'gulp'; +import * as path from 'path'; -import Paths from "../../extensions/consts/paths"; +import Paths from './../../extensions/consts/paths'; /* * > Watcher @@ -10,5 +10,5 @@ import Paths from "../../extensions/consts/paths"; export default gulp.task('watch', () => { // Commented due // gulp.watch(path.join(Paths.SRC, `./themes/**/*.json`), ['build:themes']); - gulp.watch(path.join(Paths.SRC, `./themes/**/*.json`)); -}); \ No newline at end of file + gulp.watch(path.join(Paths.SRC, './themes/**/*.json')); +}); diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ba125ba --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - '8' + +script: + - yarn test diff --git a/.vscode/settings.json b/.vscode/settings.json index e3fc186..c8a043f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "editor.tabSize": 2, "editor.insertSpaces": true, + "files.insertFinalNewline": true, "files.exclude": { "**/.git": true, ".git-crypt": true, diff --git a/README.md b/README.md index 7a9c6fb..82d6e78 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ Launch *Quick Open*, - macOS `⌘ + Shift + P` - Windows `Ctrl + Shift + P` -type `material theme` and select `Material Theme: Settings` from the drop-down menu. Here you will find the `Fix file icons` command that will set the correct icons theme based on your active material theme variant. +type `material theme` and select `Material Theme: Fix file icons` from the drop-down menu, this command will set the correct icon theme based on your active material theme variant. ## Set the accent color @@ -104,7 +104,7 @@ Launch *Quick Open*, - macOS `⌘ + Shift + P` - Windows `Ctrl + Shift + P` -Type `Material Theme` and choose `Material Theme: Settings`, then select `Change accent color` and pick one color from the list. +Type `material theme` and choose `Material Theme: Set accent color` and pick one color from the list. ## Override theme colors You can override the material theme ui and schemes colors by adding these theme-specific settings to your configuration. For advanced customisation please check the [relative section on the vs code documentation](https://code.visualstudio.com/docs/getstarted/themes#_customizing-a-color-theme) @@ -149,7 +149,6 @@ You can override the material theme ui and schemes colors by adding these theme- "[Material Theme]": { "sideBar.background": "#347890" }, - "..." } ``` diff --git a/extensions/commands/accents-setter/index.ts b/extensions/commands/accents-setter/index.ts index 3b042e6..63dd2ca 100644 --- a/extensions/commands/accents-setter/index.ts +++ b/extensions/commands/accents-setter/index.ts @@ -1,107 +1,110 @@ import * as vscode from 'vscode'; -import {IAccentCustomProperty} from '../../interfaces/iaccent-custom-property'; -import { IDefaults } from "../../interfaces/idefaults"; -import {IGenericObject} from '../../interfaces/igeneric-object'; -import { updateAccent, isMaterialTheme, isMaterialThemeIcons } from "../../helpers/settings"; -import { getCurrentThemeID, getCurrentThemeIconsID, reloadWindow } from "../../helpers/vscode"; -import { THEME_ICONS } from "../theme-icons/index"; +import {IAccentCustomProperty} from './../../interfaces/iaccent-custom-property'; +import {IGenericObject} from './../../interfaces/igeneric-object'; +import { + updateAccent, + isMaterialTheme, + isMaterialThemeIcons +} from './../../helpers/settings'; +import { + getCurrentThemeID, + getCurrentThemeIconsID, + reloadWindow +} from './../../helpers/vscode'; +import {getDefaultValues} from './../../helpers/fs'; +import {THEME_ICONS} from './../theme-icons/index'; const REGEXP_HEX: RegExp = /^#([0-9A-F]{6}|[0-9A-F]{8})$/i; -let themeConfigCommon: IDefaults = require('../../defaults.json'); -let accentsProperties: IGenericObject = { - "activityBarBadge.background": { +const accentsProperties: IGenericObject = { + 'activityBarBadge.background': { alpha: 100, value: undefined }, - "list.activeSelectionForeground": { + 'list.activeSelectionForeground': { alpha: 100, value: undefined }, - "list.inactiveSelectionForeground": { + 'list.inactiveSelectionForeground': { alpha: 100, value: undefined }, - "list.highlightForeground": { + 'list.highlightForeground': { alpha: 100, value: undefined }, - "scrollbarSlider.activeBackground": { + 'scrollbarSlider.activeBackground': { alpha: 50, value: undefined }, - "editorSuggestWidget.highlightForeground": { + 'editorSuggestWidget.highlightForeground': { alpha: 100, value: undefined }, - "textLink.foreground": { + 'textLink.foreground': { alpha: 100, value: undefined }, - "progressBar.background": { + 'progressBar.background': { alpha: 100, value: undefined }, - "pickerGroup.foreground": { + 'pickerGroup.foreground': { alpha: 100, value: undefined }, - "tab.activeBorder": { + 'tab.activeBorder': { alpha: 100, value: undefined }, - "notificationLink.foreground": { + 'notificationLink.foreground': { + alpha: 100, + value: undefined + }, + "editor.findWidgetResizeBorder": { + alpha: 100, + value: undefined + }, + "editorWidget.border": { alpha: 100, value: undefined } -} +}; /** * Assigns colours - * @param {string} colour - * @param {*} config */ -function assignColorCustomizations(colour: string, config: any): void { - if (!isValidColour(colour)) { - colour = undefined; - } +const assignColorCustomizations = (colour: string, config: any): void => { + const newColour = isValidColour(colour) ? colour : undefined; Object.keys(accentsProperties).forEach(propertyName => { - let accent: IAccentCustomProperty = accentsProperties[propertyName]; - let _colour = colour; + const accent: IAccentCustomProperty = accentsProperties[propertyName]; + let colorProp = newColour; if (colour && accent.alpha < 100) { - _colour = `${ colour }${ accent.alpha > 10 ? accent.alpha : `0${ accent.alpha }` }`; + colorProp = `${ colour }${ accent.alpha > 10 ? accent.alpha : `0${ accent.alpha }` }`; } if (accent) { - config[propertyName] = _colour; + config[propertyName] = colorProp; } }); -} +}; /** * Determines if a string is a valid colour - * @param {(string | null | undefined)} colour - * @returns {boolean} */ -function isValidColour(colour: string | null | undefined): boolean { - if (typeof colour === 'string' && REGEXP_HEX.test(colour)) { - return true; - } - return false; -} +const isValidColour = (colour: string | null | undefined): boolean => + typeof colour === 'string' && REGEXP_HEX.test(colour); /** * Sets workbench options - * @param {string} accentSelected - * @param {*} config */ -function setWorkbenchOptions(accentSelected: string | undefined, config: any): void { +const setWorkbenchOptions = (accentSelected: string | undefined, config: any): void => { vscode.workspace.getConfiguration().update('workbench.colorCustomizations', config, true).then(() => { - let themeID = getCurrentThemeID() - let themeIconsID = getCurrentThemeIconsID() + const themeID = getCurrentThemeID(); + const themeIconsID = getCurrentThemeIconsID(); updateAccent(accentSelected).then(() => { if (isMaterialTheme(themeID) && isMaterialThemeIcons(themeIconsID)) { @@ -111,32 +114,34 @@ function setWorkbenchOptions(accentSelected: string | undefined, config: any): v }, reason => { vscode.window.showErrorMessage(reason); }); -} +}; /** * VSCode command */ export const THEME_ACCENTS_SETTER = () => { + const themeConfigCommon = getDefaultValues(); // shows the quick pick dropdown - let options: string[] = Object.keys(themeConfigCommon.accents); - let purgeColourKey: string = 'Remove accents'; + const options: string[] = Object.keys(themeConfigCommon.accents); + const purgeColourKey: string = 'Remove accents'; options.push(purgeColourKey); vscode.window.showQuickPick(options).then(accentSelected => { - if (accentSelected === null || accentSelected === undefined) return; + if (accentSelected === null || accentSelected === undefined) { + return; + } - let config: any = vscode.workspace.getConfiguration().get('workbench.colorCustomizations'); + const config: any = vscode.workspace.getConfiguration().get('workbench.colorCustomizations'); - switch(accentSelected) { + switch (accentSelected) { case purgeColourKey: assignColorCustomizations(undefined, config); setWorkbenchOptions(undefined, config); - break; + break; default: assignColorCustomizations(themeConfigCommon.accents[accentSelected], config); setWorkbenchOptions(accentSelected, config); - break; } }); -} \ No newline at end of file +}; diff --git a/extensions/commands/theme-icons/index.ts b/extensions/commands/theme-icons/index.ts index 93cf51c..725a0a6 100644 --- a/extensions/commands/theme-icons/index.ts +++ b/extensions/commands/theme-icons/index.ts @@ -1,93 +1,100 @@ -import {getAccentableIcons} from '../../helpers/fs'; import * as fs from 'fs'; -import { getAbsolutePath, getDefaultValues, getThemeIconsByContributeID, getThemeIconsContribute, getVariantIcons } from "../../helpers/fs"; -import { getCurrentThemeIconsID, getCurrentThemeID } from "../../helpers/vscode"; -import { isAccent, isMaterialThemeIcons, getCustomSettings } from "../../helpers/settings"; +import { + getAccentableIcons, + getAbsolutePath, + getDefaultValues, + getThemeIconsByContributeID, + getThemeIconsContribute, + getVariantIcons +} from './../../helpers/fs'; +import { + isAccent, + isMaterialThemeIcons, + getCustomSettings +} from './../../helpers/settings'; +import {getCurrentThemeIconsID, getCurrentThemeID} from './../../helpers/vscode'; +import {CHARSET} from './../../consts/files'; +import {IPackageJSONThemeIcons} from './../../interfaces/ipackage.json'; +import {IThemeIconsIconPath, IThemeIcons} from './../../interfaces/itheme-icons'; -import { CHARSET } from "../../consts/files"; -import { IPackageJSONThemeIcons } from "../../interfaces/ipackage.json"; -import {IThemeIconsIconPath, IThemeIcons} from '../../interfaces/itheme-icons'; - - -function getIconDefinition(definitions: any, iconname: string): IThemeIconsIconPath { +const getIconDefinition = (definitions: any, iconname: string): IThemeIconsIconPath => { return (definitions as any)[iconname]; -} +}; /** * Replaces icon path with the accented one. - * @param {string} iconPath - * @param {string} accentName - * @returns {string} */ -function replaceIconPathWithAccent(iconPath: string, accentName: string): string { +const replaceIconPathWithAccent = (iconPath: string, accentName: string): string => { return iconPath.replace('.svg', `.accent.${ accentName }.svg`); -} +}; -function getVariantFromColor(color: string): string { - switch (color) { - case undefined || 'Material Theme': +const getVariantFromColor = (color: string): string => { + switch (true) { + case color === undefined || color === 'Material Theme': return 'Default'; - case 'Material Theme High Contrast': + case color === 'Material Theme High Contrast': return 'Default High Contrast'; + case color.includes('Material Theme Lighter'): + return 'Light'; default: return color.replace(/Material Theme /gi, ''); } -} +}; export const THEME_ICONS = () => { - let deferred: any = {}; - let promise = new Promise((resolve, reject) => { + const deferred: any = {}; + const promise = new Promise((resolve, reject) => { deferred.resolve = resolve; deferred.reject = reject; }); - let themeIconsID: string = getCurrentThemeIconsID(); + const themeIconsID: string = getCurrentThemeIconsID(); if (isMaterialThemeIcons(themeIconsID)) { - let themeID = getCurrentThemeID(); - let customSettings = getCustomSettings(); - let defaults = getDefaultValues(); - let accentName = customSettings.accent; - let variantName: string = getVariantFromColor(themeID); + const themeID = getCurrentThemeID(); + const customSettings = getCustomSettings(); + const defaults = getDefaultValues(); + const accentName = customSettings.accent; + const variantName: string = getVariantFromColor(themeID); - let themeContribute: IPackageJSONThemeIcons = getThemeIconsContribute(themeIconsID); - let theme: IThemeIcons = getThemeIconsByContributeID(themeIconsID); - let themepath: string = getAbsolutePath(themeContribute.path); + const themeContribute: IPackageJSONThemeIcons = getThemeIconsContribute(themeIconsID); + const theme: IThemeIcons = getThemeIconsByContributeID(themeIconsID); + const themepath: string = getAbsolutePath(themeContribute.path); if (isAccent(accentName, defaults)) { - let _accentName = accentName.replace(/\s+/, '-'); - + const realAccentName = accentName.replace(/\s+/, '-'); getAccentableIcons().forEach(iconname => { - let distIcon = getIconDefinition(theme.iconDefinitions, iconname); - let outIcon = getIconDefinition(defaults.icons.theme.iconDefinitions, iconname); + const distIcon = getIconDefinition(theme.iconDefinitions, iconname); + const outIcon = getIconDefinition(defaults.icons.theme.iconDefinitions, iconname); if (typeof distIcon === 'object' && typeof outIcon === 'object') { - distIcon.iconPath = replaceIconPathWithAccent(outIcon.iconPath, _accentName) + distIcon.iconPath = replaceIconPathWithAccent(outIcon.iconPath, realAccentName); } - }) + }); } else { - getAccentableIcons().forEach(iconname => { - let distIcon = getIconDefinition(theme.iconDefinitions, iconname); - let outIcon = getIconDefinition(defaults.icons.theme.iconDefinitions, iconname); + const distIcon = getIconDefinition(theme.iconDefinitions, iconname); + const outIcon = getIconDefinition(defaults.icons.theme.iconDefinitions, iconname); distIcon.iconPath = outIcon.iconPath; }); } getVariantIcons().forEach(iconname => { - let distIcon = getIconDefinition(theme.iconDefinitions, iconname); - let outIcon = getIconDefinition(defaults.icons.theme.iconDefinitions, iconname); + const distIcon = getIconDefinition(theme.iconDefinitions, iconname); + const outIcon = getIconDefinition(defaults.icons.theme.iconDefinitions, iconname); - if (!!distIcon && !!outIcon) { + if (distIcon && outIcon) { distIcon.iconPath = outIcon.iconPath.replace('.svg', `${ variantName }.svg`); } - }) + }); - fs.writeFile(themepath, JSON.stringify(theme), { encoding: CHARSET }, (error) => { - if (error) { - deferred.reject(error); + fs.writeFile(themepath, JSON.stringify(theme), { + encoding: CHARSET + }, err => { + if (err) { + deferred.reject(err); return; } @@ -98,4 +105,4 @@ export const THEME_ICONS = () => { } return promise; -} \ No newline at end of file +}; diff --git a/extensions/consts/files.ts b/extensions/consts/files.ts index ccde74c..63a0935 100644 --- a/extensions/consts/files.ts +++ b/extensions/consts/files.ts @@ -1,5 +1,4 @@ /** * File charset - * @type {string} */ -export const CHARSET: string = 'utf-8'; \ No newline at end of file +export const CHARSET: string = 'utf-8'; diff --git a/extensions/consts/paths.ts b/extensions/consts/paths.ts index 4f673e9..03372f0 100644 --- a/extensions/consts/paths.ts +++ b/extensions/consts/paths.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import { IPaths } from '../interfaces/ipaths'; +import {IPaths} from '../interfaces/ipaths'; export const PATHS: IPaths = { DIST: './dist', diff --git a/extensions/helpers/changelog.ts b/extensions/helpers/changelog.ts index 4fd18b9..cdd8fe6 100644 --- a/extensions/helpers/changelog.ts +++ b/extensions/helpers/changelog.ts @@ -1,61 +1,61 @@ import * as path from 'path'; import * as vscode from 'vscode'; -import { getDefaultValues, getPackageJSON, writeFile } from "./fs"; -import { PATHS } from '../consts/paths'; +import {IDefaults} from './../interfaces/idefaults'; -function previewFile(): void { - let uri = vscode.Uri.file(path.join(PATHS.VSIX_DIR, './CHANGELOG.md')); +import {getDefaultValues, getPackageJSON, writeFile} from './fs'; +import {PATHS} from './../consts/paths'; +const previewFile = (): void => { + const uri = vscode.Uri.file(path.join(PATHS.VSIX_DIR, './CHANGELOG.md')); vscode.commands.executeCommand('markdown.showPreview', uri); +}; -} +const splitVersion = (input: string): {major: number; minor: number; patch: number} => { + const [major, minor, patch] = input.split('.').map(i => parseInt(i, 10)); + return {major, minor, patch}; +}; -function splitVersion(input: string): { major: number, minor: number, patch: number } { - let [ major, minor, patch ] = input.split('.').map(i => parseInt(i)); - return { major, minor, patch }; -} +const writeDefaults = (defaults: IDefaults) => + writeFile(path.join('./extensions/defaults.json'), JSON.stringify(defaults, null, 2)); -export function showChangelog(): void { - let extname: string = 'vscode.markdown'; - let md = vscode.extensions.getExtension(extname); +export const showChangelog = (): void => { + const extname: string = 'vscode.markdown'; + const md = vscode.extensions.getExtension(extname); if (md === undefined) { - console.warn(`Ext not found ${ extname }`) + console.warn(`Ext not found ${ extname }`); return; } if (md.isActive) { - previewFile(); - } else { - md.activate().then(() => { - previewFile(); - }, reason => { - console.warn(reason); - }); - } -} - -export function shouldShowChangelog(): boolean { - let defaults = getDefaultValues(); - let out: boolean; - let packageJSON = getPackageJSON(); - - if (defaults.changelog == undefined || (defaults.changelog !== undefined && typeof defaults.changelog.lastversion !== 'string')) { - defaults.changelog = { - lastversion: packageJSON.version - } - out = true; - } else { - let versionCurrent = splitVersion(packageJSON.version); - let versionOld = splitVersion(defaults.changelog.lastversion); - - out = versionCurrent.major > versionOld.major || versionCurrent.minor > versionOld.minor || versionCurrent.patch > versionOld.patch; - - defaults.changelog.lastversion = packageJSON.version; + return previewFile(); } - writeFile(path.join('./extensions/defaults.json'), JSON.stringify(defaults, null, 2)); + md.activate() + .then(() => previewFile(), + reason => console.warn(reason) + ); +}; + +export const shouldShowChangelog = (): boolean => { + const defaults = getDefaultValues(); + const packageJSON = getPackageJSON(); + + const defaultsNotPresent = defaults.changelog === undefined || + (defaults.changelog !== undefined && typeof defaults.changelog.lastversion !== 'string'); + + const versionCurrent = splitVersion(packageJSON.version); + const versionOld = defaultsNotPresent ? null : splitVersion(defaults.changelog.lastversion); + + const out = !versionOld || + versionCurrent.major > versionOld.major || + versionCurrent.minor > versionOld.minor || + versionCurrent.patch > versionOld.patch; + + const newChangelog = {...defaults.changelog, lastversion: packageJSON.version}; + const newDefaults = {...defaults, changelog: newChangelog}; + writeDefaults(newDefaults); return out; -} \ No newline at end of file +}; diff --git a/extensions/helpers/fs.ts b/extensions/helpers/fs.ts index de5e41f..986a847 100644 --- a/extensions/helpers/fs.ts +++ b/extensions/helpers/fs.ts @@ -1,30 +1,21 @@ -import * as fs from 'fs' -import * as path from 'path' +import * as fs from 'fs'; +import * as path from 'path'; -import { IPackageJSON, IPackageJSONThemeIcons } from "../interfaces/ipackage.json"; +import {IPackageJSON, IPackageJSONThemeIcons} from './../interfaces/ipackage.json'; -import { CHARSET } from "../consts/files"; -import { IDefaults } from "../interfaces/idefaults"; -import { IThemeIcons } from "../interfaces/itheme-icons"; -import { PATHS } from "../consts/paths"; +import {CHARSET} from './../consts/files'; +import {IDefaults} from '../interfaces/idefaults'; +import {IThemeIcons} from '../interfaces/itheme-icons'; +import {PATHS} from '../consts/paths'; -/** - * @export - * @param {string} dirname - */ export function ensureDir(dirname: string): void { if (!fs.existsSync(dirname)) { fs.mkdirSync(dirname); } } -/** - * Gets default value - * @export - * @returns {IDefaults} - */ export function getDefaultValues(): IDefaults { - let defaults: IDefaults = require(path.join(PATHS.VSIX_DIR, './extensions/defaults.json')); + const defaults: IDefaults = require(path.join(PATHS.VSIX_DIR, './extensions/defaults.json')); if (defaults === undefined || defaults === null) { throw new Error('Cannot find defaults params'); @@ -33,74 +24,45 @@ export function getDefaultValues(): IDefaults { return defaults; } -/** - * Gets an absolute path - * - * @export - * @param {string} input - * @returns {string} - */ export function getAbsolutePath(input: string): string { return path.join(PATHS.VSIX_DIR, input); } -/** - * @export - * @returns {string[]} - */ export function getAccentableIcons(): string[] { return getDefaultValues().accentableIcons; } -/** - * @export - * @returns {string[]} - */ export function getVariantIcons(): string[] { return getDefaultValues().variantsIcons; } /** * Gets a theme content by a given contribute ID - * - * @export - * @param {string} ID - * @returns {IThemeIcons} */ export function getThemeIconsByContributeID(ID: string): IThemeIcons | null { - let contribute: IPackageJSONThemeIcons = getThemeIconsContribute(ID) + const contribute: IPackageJSONThemeIcons = getThemeIconsContribute(ID); return contribute !== null ? require(path.join(PATHS.VSIX_DIR, contribute.path)) : null; } /** * Gets a theme by name - * @export - * @param {string} name - * @returns {IThemeIcons} */ export function getThemeIconsContribute(ID: string): IPackageJSONThemeIcons { - let contributes = getPackageJSON().contributes.iconThemes.filter(contribute => contribute.id === ID); + const contributes = getPackageJSON().contributes.iconThemes.filter(contribute => contribute.id === ID); return contributes[0] !== undefined ? contributes[0] : null; } /** * Gets package JSON - * @export - * @returns {*} */ export function getPackageJSON(): IPackageJSON { - let packageJSON: IPackageJSON = require(path.join(PATHS.VSIX_DIR, './package.json')); - return packageJSON; + return require(path.join(PATHS.VSIX_DIR, './package.json')); } /** * Writes a file inside the vsix directory - * @export - * @param {string} filename - * @param {string} filecontent */ export function writeFile(filename: string, filecontent: string): void { - filename = path.join(PATHS.VSIX_DIR, filename); - console.log(arguments) - fs.writeFileSync(filename, filecontent, { encoding: CHARSET }); -} \ No newline at end of file + const filePath = path.join(PATHS.VSIX_DIR, filename); + fs.writeFileSync(filePath, filecontent, {encoding: CHARSET}); +} diff --git a/extensions/helpers/settings.ts b/extensions/helpers/settings.ts index e4e569c..e5b5f48 100644 --- a/extensions/helpers/settings.ts +++ b/extensions/helpers/settings.ts @@ -1,13 +1,11 @@ import * as vscode from 'vscode'; -import { IDefaults } from "../interfaces/idefaults"; -import { IThemeCustomProperties } from "../interfaces/itheme-custom-properties"; +import {IDefaults} from './../interfaces/idefaults'; +import {IThemeCustomProperties} from './../interfaces/itheme-custom-properties'; import {getPackageJSON} from './fs'; /** * Gets saved accent - * @export - * @returns {(string | null)} */ export function getAccent(): string | undefined { return getCustomSettings().accent; @@ -15,8 +13,6 @@ export function getAccent(): string | undefined { /** * Gets custom settings - * @export - * @returns {*} */ export function getCustomSettings(): IThemeCustomProperties { return vscode.workspace.getConfiguration().get('materialTheme', {}); @@ -24,10 +20,6 @@ export function getCustomSettings(): IThemeCustomProperties { /** * Checks if a given string could be an accent - * - * @export - * @param {string} accentName - * @returns {boolean} */ export function isAccent(accentName: string, defaults: IDefaults): boolean { return Object.keys(defaults.accents).filter(name => name === accentName).length > 0; @@ -35,31 +27,22 @@ export function isAccent(accentName: string, defaults: IDefaults): boolean { /** * Determines if the passing theme label is a material theme - * @export - * @param {string} themeName - * @returns {boolean} */ export function isMaterialTheme(themeName: string): boolean { - let packageJSON = getPackageJSON(); + const packageJSON = getPackageJSON(); return packageJSON.contributes.themes.filter(contrib => contrib.label === themeName).length > 0; } /** * Determines if the passing icons theme is a material theme - * @export - * @param {string} themeIconsName - * @returns {boolean} */ export function isMaterialThemeIcons(themeIconsName: string): boolean { - let packageJSON = getPackageJSON(); + const packageJSON = getPackageJSON(); return packageJSON.contributes.iconThemes.filter(contribute => contribute.id === themeIconsName).length > 0; } /** * Sets a custom property in custom settings - * @export - * @param {string} settingName - * @param {*} value */ export function setCustomSetting(settingName: string, value: any): Thenable { return vscode.workspace.getConfiguration().update(`materialTheme.${settingName}`, value, true); @@ -67,11 +50,9 @@ export function setCustomSetting(settingName: string, value: any): Thenable { const prevAccent = getAccent(); return setCustomSetting('accentPrevious', prevAccent) - .then(() => setCustomSetting('accent', accentName)) -} \ No newline at end of file + .then(() => setCustomSetting('accent', accentName)); +} diff --git a/extensions/helpers/vscode.ts b/extensions/helpers/vscode.ts index 2f38245..911024d 100644 --- a/extensions/helpers/vscode.ts +++ b/extensions/helpers/vscode.ts @@ -1,24 +1,22 @@ -import * as vscode from 'vscode' - +import * as vscode from 'vscode'; export function askForWindowReload(): Thenable { const PROMPT_MESSAGE: string = 'Material Theme requires VS Code reload in order to display icons correctly.'; const PROMPT_MESSAGE_CONFIRM: string = 'Ok, reload'; const PROMPT_MESSAGE_CANCEL: string = 'I will do it later'; - return vscode.window.showInformationMessage(PROMPT_MESSAGE, PROMPT_MESSAGE_CONFIRM, PROMPT_MESSAGE_CANCEL).then((response) => { - if (response === PROMPT_MESSAGE_CONFIRM) { - reloadWindow(); - } - }, (error) => { - console.log(error); - }); + return vscode.window.showInformationMessage(PROMPT_MESSAGE, PROMPT_MESSAGE_CONFIRM, PROMPT_MESSAGE_CANCEL) + .then(response => { + if (response === PROMPT_MESSAGE_CONFIRM) { + reloadWindow(); + } + }, err => { + console.log(err); + }); } /** * Gets your current theme ID - * @export - * @returns {string} */ export function getCurrentThemeID(): string { return vscode.workspace.getConfiguration().get('workbench.colorTheme'); @@ -26,8 +24,6 @@ export function getCurrentThemeID(): string { /** * Gets your current icons theme ID - * @export - * @returns {string} */ export function getCurrentThemeIconsID(): string { return vscode.workspace.getConfiguration().get('workbench.iconTheme'); @@ -35,8 +31,6 @@ export function getCurrentThemeIconsID(): string { /** * Set a specific id for icons - * @export - * @returns {Thenable} */ export function setIconsID(id: string): Thenable { return vscode.workspace.getConfiguration().update('workbench.iconTheme', id, true); @@ -44,8 +38,7 @@ export function setIconsID(id: string): Thenable { /** * Reloads current vscode window. - * @export */ export function reloadWindow(): void { vscode.commands.executeCommand('workbench.action.reloadWindow'); -} \ No newline at end of file +} diff --git a/extensions/interfaces/iaccent-custom-property.ts b/extensions/interfaces/iaccent-custom-property.ts index 6b6b81d..3c2ca51 100644 --- a/extensions/interfaces/iaccent-custom-property.ts +++ b/extensions/interfaces/iaccent-custom-property.ts @@ -1,4 +1,4 @@ export interface IAccentCustomProperty { alpha: number; value: any; -} \ No newline at end of file +} diff --git a/extensions/interfaces/idefaults.ts b/extensions/interfaces/idefaults.ts index 4e4ee50..e989c20 100644 --- a/extensions/interfaces/idefaults.ts +++ b/extensions/interfaces/idefaults.ts @@ -4,9 +4,10 @@ export interface IDefaults { changelog: IChangelog; icons: IDefaultsThemeIcons; themeVariants: IDefaultsThemeVariant; - themeVariantsColours: IDefaultsThemeVariantColours; - themeVariantsUITheme: IDefaultsThemeVariantUITheme; + themeVariantsColours: IDefaultsThemeVariant; + themeVariantsUITheme: IDefaultsThemeVariant; variantsIcons: string[]; + [Symbol.iterator](): IterableIterator; } export interface IAccents { @@ -16,6 +17,7 @@ export interface IAccents { export interface IChangelog { lastversion: string; + [Symbol.iterator](): IterableIterator; } export interface IDefaultsThemeIcons { @@ -23,24 +25,24 @@ export interface IDefaultsThemeIcons { iconDefinitions: { _folder_open: { iconPath: string; - } + }; _folder_open_build: { iconPath: string; - } + }; _folder_dark: { iconPath: string; - } + }; _folder_dark_build: { iconPath: string; - } - "_folder_light_build": { + }; + _folder_light_build: { iconPath: string; - } + }; _folder_light: { iconPath: string; - } - } - } + }; + }; + }; } export interface IDefaultsThemeVariant { @@ -53,11 +55,3 @@ export interface IDefaultsThemeVariant { LightHighContrast: string; PalenightHighContrast: string; } - -export interface IDefaultsThemeVariantColours extends IDefaultsThemeVariant { - -} - -export interface IDefaultsThemeVariantUITheme extends IDefaultsThemeVariant { - -} \ No newline at end of file diff --git a/extensions/interfaces/igeneric-object.ts b/extensions/interfaces/igeneric-object.ts index 7631326..d0515f4 100644 --- a/extensions/interfaces/igeneric-object.ts +++ b/extensions/interfaces/igeneric-object.ts @@ -1,3 +1,3 @@ export interface IGenericObject { [index: string]: TValue; -} \ No newline at end of file +} diff --git a/extensions/interfaces/ipackage.json.ts b/extensions/interfaces/ipackage.json.ts index b52a9f7..edd732a 100644 --- a/extensions/interfaces/ipackage.json.ts +++ b/extensions/interfaces/ipackage.json.ts @@ -1,4 +1,4 @@ -import { IGenericObject } from '../../extensions/interfaces/igeneric-object'; +import {IGenericObject} from './../../extensions/interfaces/igeneric-object'; export interface IPackageJSONBadge { description: string; @@ -14,9 +14,7 @@ export interface IPackageJSONContributes { } export interface IPackageJSONConfiguration { - properties: { - - } + properties: {}; } export interface IPackageJSONCommand { @@ -38,24 +36,24 @@ export interface IPackageJSONThemeIcons { } export interface IPackageJSON { - "activationEvents": string[] - "badges": IPackageJSONBadge[]; - "contributes": IPackageJSONContributes; - "bugs": IGenericObject; - "categories": string[]; - "description": string; - "displayName": string; - "engines": IGenericObject; - "galleryBanner": IGenericObject; - "homepage": string; - "icon": string; - "license": string; - "main": string; - "name": string; - "preview": boolean; - "publisher": string; - "repository": IGenericObject; - "scripts": IGenericObject; - "version": string; - "devDependencies": IGenericObject; -} \ No newline at end of file + activationEvents: string[]; + badges: IPackageJSONBadge[]; + contributes: IPackageJSONContributes; + bugs: IGenericObject; + categories: string[]; + description: string; + displayName: string; + engines: IGenericObject; + galleryBanner: IGenericObject; + homepage: string; + icon: string; + license: string; + main: string; + name: string; + preview: boolean; + publisher: string; + repository: IGenericObject; + scripts: IGenericObject; + version: string; + devDependencies: IGenericObject; +} diff --git a/extensions/interfaces/ipaths.ts b/extensions/interfaces/ipaths.ts index ba3d072..1a22e32 100644 --- a/extensions/interfaces/ipaths.ts +++ b/extensions/interfaces/ipaths.ts @@ -1,32 +1,22 @@ export interface IPaths { /** * Dist dir - * @type {string} - * @memberof IPaths */ DIST: string; /** * Icons dir - * @type {string} - * @memberof IPaths */ ICONS: string; /** * Src dir - * @type {string} - * @memberof IPaths */ SRC: string; /** * Themes dir - * @type {string} - * @memberof IPaths */ THEMES: string; /** * Extension directory - * @type {string} - * @memberof IPaths */ VSIX_DIR: string; -} \ No newline at end of file +} diff --git a/extensions/interfaces/itheme-custom-properties.ts b/extensions/interfaces/itheme-custom-properties.ts index 3bd1bc2..4d7a858 100644 --- a/extensions/interfaces/itheme-custom-properties.ts +++ b/extensions/interfaces/itheme-custom-properties.ts @@ -1,4 +1,4 @@ export interface IThemeCustomProperties { accent?: string; accentPrevious?: string; -} \ No newline at end of file +} diff --git a/extensions/interfaces/itheme-icons.ts b/extensions/interfaces/itheme-icons.ts index 23e10f6..4d6cd8b 100644 --- a/extensions/interfaces/itheme-icons.ts +++ b/extensions/interfaces/itheme-icons.ts @@ -3,511 +3,514 @@ export interface IThemeIconsIconPath { } export interface IThemeIcons { - "iconDefinitions": - { - "_folder_dark": IThemeIconsIconPath; - "_file_folder": IThemeIconsIconPath; - "_folder_dark_build": IThemeIconsIconPath; - "_folder_light": IThemeIconsIconPath; - "_folder_light_build": IThemeIconsIconPath; - "_folder_open": IThemeIconsIconPath; - "_folder_open_build": IThemeIconsIconPath; - "_file_dark": IThemeIconsIconPath; - "_file_actionscript": IThemeIconsIconPath; - "_file_ai": IThemeIconsIconPath; - "_file_android": IThemeIconsIconPath; - "_file_angular": IThemeIconsIconPath; - "_file_applescript": IThemeIconsIconPath; - "_file_arduino": IThemeIconsIconPath; - "_file_assembly": IThemeIconsIconPath; - "_file_autohotkey": IThemeIconsIconPath; - "_file_bower": IThemeIconsIconPath; - "_file_c": IThemeIconsIconPath; - "_file_certificate": IThemeIconsIconPath; - "_file_changelog": IThemeIconsIconPath; - "_file_clojure": IThemeIconsIconPath; - "_file_cmake": IThemeIconsIconPath; - "_file_cmd": IThemeIconsIconPath; - "_file_coffee": IThemeIconsIconPath; - "_file_console": IThemeIconsIconPath; - "_file_contributing": IThemeIconsIconPath; - "_file_cpp": IThemeIconsIconPath; - "_file_credits": IThemeIconsIconPath; - "_file_csharp": IThemeIconsIconPath; - "_file_css-map": IThemeIconsIconPath; - "_file_css": IThemeIconsIconPath; - "_file_dart": IThemeIconsIconPath; - "_file_database": IThemeIconsIconPath; - "_file_dlang": IThemeIconsIconPath; - "_file_docker": IThemeIconsIconPath; - "_file_document": IThemeIconsIconPath; - "_file_email": IThemeIconsIconPath; - "_file_exe": IThemeIconsIconPath; - "_file_favicon": IThemeIconsIconPath; - "_file_file": IThemeIconsIconPath; - "_file_flash": IThemeIconsIconPath; - "_file_flow": IThemeIconsIconPath; - "_file_folder-build": IThemeIconsIconPath; - "_file_folder-light-build": IThemeIconsIconPath; - "_file_folder-light": IThemeIconsIconPath; - "_file_folder-outline-build": IThemeIconsIconPath; - "_file_folder-outline": IThemeIconsIconPath; - "_file_font": IThemeIconsIconPath; - "_file_fsharp": IThemeIconsIconPath; - "_file_git": IThemeIconsIconPath; - "_file_github": IThemeIconsIconPath; - "_file_go": IThemeIconsIconPath; - "_file_gopher": IThemeIconsIconPath; - "_file_gradle": IThemeIconsIconPath; - "_file_graphql": IThemeIconsIconPath; - "_file_groovy": IThemeIconsIconPath; - "_file_grunt": IThemeIconsIconPath; - "_file_gulp": IThemeIconsIconPath; - "_file_haml": IThemeIconsIconPath; - "_file_haskell": IThemeIconsIconPath; - "_file_html": IThemeIconsIconPath; - "_file_image": IThemeIconsIconPath; - "_file_ionic": IThemeIconsIconPath; - "_file_java": IThemeIconsIconPath; - "_file_javascript-map": IThemeIconsIconPath; - "_file_js": IThemeIconsIconPath; - "_file_json": IThemeIconsIconPath; - "_file_key": IThemeIconsIconPath; - "_file_kotlin": IThemeIconsIconPath; - "_file_less": IThemeIconsIconPath; - "_file_lib": IThemeIconsIconPath; - "_file_license": IThemeIconsIconPath; - "_file_lua": IThemeIconsIconPath; - "_file_markdown": IThemeIconsIconPath; - "_file_markup": IThemeIconsIconPath; - "_file_movie": IThemeIconsIconPath; - "_file_music": IThemeIconsIconPath; - "_file_mustache": IThemeIconsIconPath; - "_file_mxml": IThemeIconsIconPath; - "_file_nodejs": IThemeIconsIconPath; - "_file_npm": IThemeIconsIconPath; - "_file_ocaml": IThemeIconsIconPath; - "_file_pdf": IThemeIconsIconPath; - "_file_php": IThemeIconsIconPath; - "_file_polymer": IThemeIconsIconPath; - "_file_postcss": IThemeIconsIconPath; - "_file_powerpoint": IThemeIconsIconPath; - "_file_pp": IThemeIconsIconPath; - "_file_procfile": IThemeIconsIconPath; - "_file_pug": IThemeIconsIconPath; - "_file_python": IThemeIconsIconPath; - "_file_r": IThemeIconsIconPath; - "_file_rails": IThemeIconsIconPath; - "_file_raml": IThemeIconsIconPath; - "_file_react": IThemeIconsIconPath; - "_file_readme": IThemeIconsIconPath; - "_file_ruby": IThemeIconsIconPath; - "_file_rust": IThemeIconsIconPath; - "_file_sass": IThemeIconsIconPath; - "_file_settings": IThemeIconsIconPath; - "_file_sketch": IThemeIconsIconPath; - "_file_star": IThemeIconsIconPath; - "_file_stylus": IThemeIconsIconPath; - "_file_sublime": IThemeIconsIconPath; - "_file_svg": IThemeIconsIconPath; - "_file_swc": IThemeIconsIconPath; - "_file_swift": IThemeIconsIconPath; - "_file_swig": IThemeIconsIconPath; - "_file_table": IThemeIconsIconPath; - "_file_tex": IThemeIconsIconPath; - "_file_todo": IThemeIconsIconPath; - "_file_tune": IThemeIconsIconPath; - "_file_twig": IThemeIconsIconPath; - "_file_typescript": IThemeIconsIconPath; - "_file_typescript_def": IThemeIconsIconPath; - "_file_url": IThemeIconsIconPath; - "_file_virtual": IThemeIconsIconPath; - "_file_visualstudio": IThemeIconsIconPath; - "_file_vue": IThemeIconsIconPath; - "_file_webpack": IThemeIconsIconPath; - "_file_word": IThemeIconsIconPath; - "_file_xaml": IThemeIconsIconPath; - "_file_xml": IThemeIconsIconPath; - "_file_yaml": IThemeIconsIconPath; - "_file_yarn": IThemeIconsIconPath; - "_file_zip": IThemeIconsIconPath; + iconDefinitions: { + _folder_dark: IThemeIconsIconPath; + _file_folder: IThemeIconsIconPath; + _folder_dark_build: IThemeIconsIconPath; + _folder_light: IThemeIconsIconPath; + _folder_light_build: IThemeIconsIconPath; + _folder_open: IThemeIconsIconPath; + _folder_open_build: IThemeIconsIconPath; + _file_dark: IThemeIconsIconPath; + _file_actionscript: IThemeIconsIconPath; + _file_ai: IThemeIconsIconPath; + _file_android: IThemeIconsIconPath; + _file_angular: IThemeIconsIconPath; + _file_applescript: IThemeIconsIconPath; + _file_arduino: IThemeIconsIconPath; + _file_assembly: IThemeIconsIconPath; + _file_autohotkey: IThemeIconsIconPath; + _file_bower: IThemeIconsIconPath; + _file_c: IThemeIconsIconPath; + _file_certificate: IThemeIconsIconPath; + _file_changelog: IThemeIconsIconPath; + _file_clojure: IThemeIconsIconPath; + _file_cmake: IThemeIconsIconPath; + _file_cmd: IThemeIconsIconPath; + _file_coffee: IThemeIconsIconPath; + _file_console: IThemeIconsIconPath; + _file_contributing: IThemeIconsIconPath; + _file_cpp: IThemeIconsIconPath; + _file_credits: IThemeIconsIconPath; + _file_csharp: IThemeIconsIconPath; + '_file_css-map': IThemeIconsIconPath; + _file_css: IThemeIconsIconPath; + _file_dart: IThemeIconsIconPath; + _file_database: IThemeIconsIconPath; + _file_dlang: IThemeIconsIconPath; + _file_docker: IThemeIconsIconPath; + _file_document: IThemeIconsIconPath; + _file_email: IThemeIconsIconPath; + _file_exe: IThemeIconsIconPath; + _file_favicon: IThemeIconsIconPath; + _file_file: IThemeIconsIconPath; + _file_flash: IThemeIconsIconPath; + _file_flow: IThemeIconsIconPath; + '_file_folder-build': IThemeIconsIconPath; + '_file_folder-light-build': IThemeIconsIconPath; + '_file_folder-light': IThemeIconsIconPath; + '_file_folder-outline-build': IThemeIconsIconPath; + '_file_folder-outline': IThemeIconsIconPath; + _file_font: IThemeIconsIconPath; + _file_fsharp: IThemeIconsIconPath; + _file_git: IThemeIconsIconPath; + _file_github: IThemeIconsIconPath; + _file_go: IThemeIconsIconPath; + _file_gopher: IThemeIconsIconPath; + _file_gradle: IThemeIconsIconPath; + _file_graphql: IThemeIconsIconPath; + _file_groovy: IThemeIconsIconPath; + _file_grunt: IThemeIconsIconPath; + _file_gulp: IThemeIconsIconPath; + _file_haml: IThemeIconsIconPath; + _file_haskell: IThemeIconsIconPath; + _file_html: IThemeIconsIconPath; + _file_image: IThemeIconsIconPath; + _file_ionic: IThemeIconsIconPath; + _file_java: IThemeIconsIconPath; + '_file_javascript-map': IThemeIconsIconPath; + _file_js: IThemeIconsIconPath; + _file_json: IThemeIconsIconPath; + _file_key: IThemeIconsIconPath; + _file_kotlin: IThemeIconsIconPath; + _file_less: IThemeIconsIconPath; + _file_lib: IThemeIconsIconPath; + _file_license: IThemeIconsIconPath; + _file_lua: IThemeIconsIconPath; + _file_markdown: IThemeIconsIconPath; + _file_markup: IThemeIconsIconPath; + _file_movie: IThemeIconsIconPath; + _file_music: IThemeIconsIconPath; + _file_mustache: IThemeIconsIconPath; + _file_mxml: IThemeIconsIconPath; + _file_nodejs: IThemeIconsIconPath; + _file_npm: IThemeIconsIconPath; + _file_ocaml: IThemeIconsIconPath; + _file_pdf: IThemeIconsIconPath; + _file_php: IThemeIconsIconPath; + _file_polymer: IThemeIconsIconPath; + _file_postcss: IThemeIconsIconPath; + _file_powerpoint: IThemeIconsIconPath; + _file_pp: IThemeIconsIconPath; + _file_procfile: IThemeIconsIconPath; + _file_pug: IThemeIconsIconPath; + _file_python: IThemeIconsIconPath; + _file_r: IThemeIconsIconPath; + _file_rails: IThemeIconsIconPath; + _file_raml: IThemeIconsIconPath; + _file_react: IThemeIconsIconPath; + _file_readme: IThemeIconsIconPath; + _file_ruby: IThemeIconsIconPath; + _file_rust: IThemeIconsIconPath; + _file_sass: IThemeIconsIconPath; + _file_settings: IThemeIconsIconPath; + _file_sketch: IThemeIconsIconPath; + _file_star: IThemeIconsIconPath; + _file_stylus: IThemeIconsIconPath; + _file_sublime: IThemeIconsIconPath; + _file_svg: IThemeIconsIconPath; + _file_swc: IThemeIconsIconPath; + _file_swift: IThemeIconsIconPath; + _file_swig: IThemeIconsIconPath; + _file_table: IThemeIconsIconPath; + _file_tex: IThemeIconsIconPath; + _file_todo: IThemeIconsIconPath; + _file_tune: IThemeIconsIconPath; + _file_twig: IThemeIconsIconPath; + _file_typescript: IThemeIconsIconPath; + _file_typescript_def: IThemeIconsIconPath; + _file_url: IThemeIconsIconPath; + _file_virtual: IThemeIconsIconPath; + _file_visualstudio: IThemeIconsIconPath; + _file_vue: IThemeIconsIconPath; + _file_webpack: IThemeIconsIconPath; + _file_word: IThemeIconsIconPath; + _file_xaml: IThemeIconsIconPath; + _file_xml: IThemeIconsIconPath; + _file_yaml: IThemeIconsIconPath; + _file_yarn: IThemeIconsIconPath; + _file_zip: IThemeIconsIconPath; }; - "fileExtensions": - { - "cmd": string; - "mustache": string; - "rails": string; - "styl": string; - "twig": string; - "swig": string; - "sketch": string; - "do": string; - "sublime-settings": string; - "sublime-theme": string; - "sublime-commands": string; - "sublime-menu": string; - "html": string; - "jade": string; - "pug": string; - "md": string; - "md.rendered": string; - "markdown": string; - "markdown.rendered": string; - "css": string; - "postcss": string; - "scss": string; - "sass": string; - "less": string; - "json": string; - "yaml": string; - "YAML-tmLanguage": string; - "yml": string; - "xml": string; - "plist": string; - "xsd": string; - "dtd": string; - "xsl": string; - "xslt": string; - "resx": string; - "iml": string; - "xquery": string; - "tmLanguage": string; - "png": string; - "jpeg": string; - "jpg": string; - "gif": string; - "svg": string; - "eps": string; - "ai": string; - "ico": string; - "tif": string; - "tiff": string; - "psd": string; - "psb": string; - "ami": string; - "apx": string; - "bmp": string; - "bpg": string; - "brk": string; - "cur": string; - "dds": string; - "dng": string; - "exr": string; - "fpx": string; - "gbr": string; - "img": string; - "jbig2": string; - "jb2": string; - "jng": string; - "jxr": string; - "pbm": string; - "pgf": string; - "pic": string; - "raw": string; - "webp": string; - "php": string; - "js": string; - "ejs": string; - "jsx": string; - "ini": string; - "dlc": string; - "dll": string; - "config": string; - "conf": string; - "esx": string; - "ts": string; - "tsx": string; - "d.ts": string; - "pdf": string; - "xlsx": string; - "xls": string; - "csv": string; - "vscodeignore": string; - "vsixmanifest": string; - "suo": string; - "sln": string; - "pdb": string; - "cs": string; - "csx": string; - "csproj": string; - "zip": string; - "tar": string; - "gz": string; - "xz": string; - "bzip2": string; - "gzip": string; - "7z": string; - "7zip": string; - "pzip": string; - "wim": string; - "rar": string; - "tgz": string; - "exe": string; - "msi": string; - "java": string; - "jar": string; - "jsp": string; - "c": string; - "h": string; - "m": string; - "cc": string; - "cpp": string; - "c++": string; - "hpp": string; - "mm": string; - "cxx": string; - "go": string; - "py": string; - "url": string; - "sh": string; - "bat": string; - "ps1": string; - "fish": string; - "bash": string; - "gradle": string; - "doc": string; - "docx": string; - "rtf": string; - "properties": string; - "prop": string; - "settings": string; - "sql": string; - "accdb": string; - "mdb": string; - "cer": string; - "cert": string; - "crt": string; - "pub": string; - "key": string; - "pem": string; - "asc": string; - "woff": string; - "woff2": string; - "ttf": string; - "eot": string; - "suit": string; - "otf": string; - "bmap": string; - "fnt": string; - "odttf": string; - "ttc": string; - "font": string; - "fonts": string; - "sui": string; - "ntf": string; - "mrf": string; - "lib": string; - "rb": string; - "erb": string; - "fs": string; - "fsx": string; - "fsi": string; - "fsproj": string; - "manifest": string; - "swift": string; - "ino": string; - "dockerignore": string; - "tex": string; - "bib": string; - "pptx": string; - "ppt": string; - "pptm": string; - "potx": string; - "pot": string; - "potm": string; - "ppsx": string; - "ppsm": string; - "pps": string; - "ppam": string; - "ppa": string; - "webm": string; - "mkv": string; - "flv": string; - "vob": string; - "ogv": string; - "ogg": string; - "gifv": string; - "avi": string; - "mov": string; - "qt": string; - "wmv": string; - "yuv": string; - "rm": string; - "rmvb": string; - "mp4": string; - "m4v": string; - "mpg": string; - "mp2": string; - "mpeg": string; - "mpe": string; - "mpv": string; - "m2v": string; - "vdi": string; - "vbox": string; - "vbox-prev": string; - "ics": string; - "mp3": string; - "flac": string; - "m4a": string; - "wma": string; - "aiff": string; - "coffee": string; - "txt": string; - "sqlite": string; - "graphql": string; - "gql": string; - "props": string; - "toml": string; - "rs": string; - "raml": string; - "xaml": string; - "prefs": string; - "hs": string; - "kt": string; - "project": string; - "patch": string; - "dockerfile": string; - "vb": string; - "lua": string; - "clj": string; - "groovy": string; - "r": string; - "rst": string; - "dart": string; - "as": string; - "mxml": string; - "ahk": string; - "swf": string; - "swc": string; - "cmake": string; - "asm": string; - "a51": string; - "inc": string; - "nasm": string; - "s": string; - "ms": string; - "agc": string; - "ags": string; - "aea": string; - "argus": string; - "mitigus": string; - "binsource": string; - "vue": string; - "ml": string; - "mli": string; - "cmx": string; - "js.map": string; - "css.map": string; - "tmTheme": string; - "pp": string; - "applescript": string; - "haml": string }; - "fileNames": - { "gruntfile.js": string; - "bower.json": string; - ".bowerrc": string; - "webpack.js": string; - "webpack.config.js": string; - "webpack.dev.js": string; - "webpack.prod.js": string; - "webpack.common.js": string; - "webpackfile.js": string; - "ionic.config.json": string; - ".io-config.json": string; - "gulpfile.js": string; - "gulpfile.babel.js": string; - "package.json": string; - "gradle.properties": string; - "gradlew": string; - ".jscsrc": string; - ".jshintrc": string; - ".jshintignore": string; - ".npmignore": string; - "tsconfig.json": string; - "tslint.json": string; - "androidmanifest.xml": string; - "gradle-wrapper.properties": string; - ".editorconfig": string; - "procfile": string; - ".env": string; - "dockerfile": string; - "license": string; - "license.md": string; - "license.md.rendered": string; - "license.txt": string; - ".babelrc": string; - ".eslintrc": string; - ".buildignore": string; - ".htaccess": string; - "composer.lock": string; - ".gitignore": string; - ".gitconfig": string; - ".gitattributes": string; - ".gitmodules": string; - ".gitkeep": string; - "yarn.lock": string; - ".yarnclean": string; - ".yarn-integrity": string; - "yarn-error.log": string; - "contributing.md": string; - "contributing.md.rendered": string; - "readme.md": string; - "readme.md.rendered": string; - ".mailmap": string; - "makefile": string; - "changelog": string; - "changelog.md": string; - "changelog.md.rendered": string; - "CREDITS": string; - "credits.txt": string; - "credits.md": string; - "credits.md.rendered": string; - ".flowconfig": string; - ".jsbeautifyrc": string; - "git-history": string; - "angular-cli.json": string; - "app.module.ts": string; - "favicon.ico": string }; - "file": string; - "folder": string; - "folderExpanded": string; - "languageIds": - { "git": string }; - "light": - { - "folderExpanded": string; - "folder": string; - "folderNames": - { "node_modules": string; - ".git": string; - ".github": string; - ".gulp": string; - "bower_components": string; - "build": string; - "dist": string }; - "folderNamesExpanded": - { "node_modules": string; - ".git": string; - ".github": string; - ".gulp": string; - "bower_components": string; - "build": string; - "dist": string } + fileExtensions: { + cmd: string; + mustache: string; + rails: string; + styl: string; + twig: string; + swig: string; + sketch: string; + do: string; + 'sublime-settings': string; + 'sublime-theme': string; + 'sublime-commands': string; + 'sublime-menu': string; + html: string; + jade: string; + pug: string; + md: string; + 'md.rendered': string; + markdown: string; + 'markdown.rendered': string; + css: string; + postcss: string; + scss: string; + sass: string; + less: string; + json: string; + yaml: string; + 'YAML-tmLanguage': string; + yml: string; + xml: string; + plist: string; + xsd: string; + dtd: string; + xsl: string; + xslt: string; + resx: string; + iml: string; + xquery: string; + tmLanguage: string; + png: string; + jpeg: string; + jpg: string; + gif: string; + svg: string; + eps: string; + ai: string; + ico: string; + tif: string; + tiff: string; + psd: string; + psb: string; + ami: string; + apx: string; + bmp: string; + bpg: string; + brk: string; + cur: string; + dds: string; + dng: string; + exr: string; + fpx: string; + gbr: string; + img: string; + jbig2: string; + jb2: string; + jng: string; + jxr: string; + pbm: string; + pgf: string; + pic: string; + raw: string; + webp: string; + php: string; + js: string; + ejs: string; + jsx: string; + ini: string; + dlc: string; + dll: string; + config: string; + conf: string; + esx: string; + ts: string; + tsx: string; + 'd.ts': string; + pdf: string; + xlsx: string; + xls: string; + csv: string; + vscodeignore: string; + vsixmanifest: string; + suo: string; + sln: string; + pdb: string; + cs: string; + csx: string; + csproj: string; + zip: string; + tar: string; + gz: string; + xz: string; + bzip2: string; + gzip: string; + '7z': string; + '7zip': string; + pzip: string; + wim: string; + rar: string; + tgz: string; + exe: string; + msi: string; + java: string; + jar: string; + jsp: string; + c: string; + h: string; + m: string; + cc: string; + cpp: string; + 'c++': string; + hpp: string; + mm: string; + cxx: string; + go: string; + py: string; + url: string; + sh: string; + bat: string; + ps1: string; + fish: string; + bash: string; + gradle: string; + doc: string; + docx: string; + rtf: string; + properties: string; + prop: string; + settings: string; + sql: string; + accdb: string; + mdb: string; + cer: string; + cert: string; + crt: string; + pub: string; + key: string; + pem: string; + asc: string; + woff: string; + woff2: string; + ttf: string; + eot: string; + suit: string; + otf: string; + bmap: string; + fnt: string; + odttf: string; + ttc: string; + font: string; + fonts: string; + sui: string; + ntf: string; + mrf: string; + lib: string; + rb: string; + erb: string; + fs: string; + fsx: string; + fsi: string; + fsproj: string; + manifest: string; + swift: string; + ino: string; + dockerignore: string; + tex: string; + bib: string; + pptx: string; + ppt: string; + pptm: string; + potx: string; + pot: string; + potm: string; + ppsx: string; + ppsm: string; + pps: string; + ppam: string; + ppa: string; + webm: string; + mkv: string; + flv: string; + vob: string; + ogv: string; + ogg: string; + gifv: string; + avi: string; + mov: string; + qt: string; + wmv: string; + yuv: string; + rm: string; + rmvb: string; + mp4: string; + m4v: string; + mpg: string; + mp2: string; + mpeg: string; + mpe: string; + mpv: string; + m2v: string; + vdi: string; + vbox: string; + 'vbox-prev': string; + ics: string; + mp3: string; + flac: string; + m4a: string; + wma: string; + aiff: string; + coffee: string; + txt: string; + sqlite: string; + graphql: string; + gql: string; + props: string; + toml: string; + rs: string; + raml: string; + xaml: string; + prefs: string; + hs: string; + kt: string; + project: string; + patch: string; + dockerfile: string; + vb: string; + lua: string; + clj: string; + groovy: string; + r: string; + rst: string; + dart: string; + as: string; + mxml: string; + ahk: string; + swf: string; + swc: string; + cmake: string; + asm: string; + a51: string; + inc: string; + nasm: string; + s: string; + ms: string; + agc: string; + ags: string; + aea: string; + argus: string; + mitigus: string; + binsource: string; + vue: string; + ml: string; + mli: string; + cmx: string; + 'js.map': string; + 'css.map': string; + tmTheme: string; + pp: string; + applescript: string; + haml: string; + }; + fileNames: { + 'gruntfile.js': string; + 'bower.json': string; + '.bowerrc': string; + 'webpack.js': string; + 'webpack.config.js': string; + 'webpack.dev.js': string; + 'webpack.prod.js': string; + 'webpack.common.js': string; + 'webpackfile.js': string; + 'ionic.config.json': string; + '.io-config.json': string; + 'gulpfile.js': string; + 'gulpfile.babel.js': string; + 'package.json': string; + 'gradle.properties': string; + gradlew: string; + '.jscsrc': string; + '.jshintrc': string; + '.jshintignore': string; + '.npmignore': string; + 'tsconfig.json': string; + 'tslint.json': string; + 'androidmanifest.xml': string; + 'gradle-wrapper.properties': string; + '.editorconfig': string; + procfile: string; + '.env': string; + dockerfile: string; + license: string; + 'license.md': string; + 'license.md.rendered': string; + 'license.txt': string; + '.babelrc': string; + '.eslintrc': string; + '.buildignore': string; + '.htaccess': string; + 'composer.lock': string; + '.gitignore': string; + '.gitconfig': string; + '.gitattributes': string; + '.gitmodules': string; + '.gitkeep': string; + 'yarn.lock': string; + '.yarnclean': string; + '.yarn-integrity': string; + 'yarn-error.log': string; + 'contributing.md': string; + 'contributing.md.rendered': string; + 'readme.md': string; + 'readme.md.rendered': string; + '.mailmap': string; + makefile: string; + changelog: string; + 'changelog.md': string; + 'changelog.md.rendered': string; + CREDITS: string; + 'credits.txt': string; + 'credits.md': string; + 'credits.md.rendered': string; + '.flowconfig': string; + '.jsbeautifyrc': string; + 'git-history': string; + 'angular-cli.json': string; + 'app.module.ts': string; + 'favicon.ico': string; + }; + file: string; + folder: string; + folderExpanded: string; + languageIds: + { git: string }; + light: { + folderExpanded: string; + folder: string; + folderNames: { + node_modules: string; + '.git': string; + '.github': string; + '.gulp': string; + bower_components: string; + build: string; + dist: string; + }; + folderNamesExpanded: { + node_modules: string; + '.git': string; + '.github': string; + '.gulp': string; + bower_components: string; + build: string; + dist: string; + }; + }; + folderNames: { + node_modules: string; + '.git': string; + '.github': string; + '.gulp': string; + bower_components: string; + build: string; + dist: string; + }; + folderNamesExpanded: { + node_modules: string; + '.git': string; + '.github': string; + '.gulp': string; + bower_components: string; + build: string; + dist: string; }; - "folderNames": - { "node_modules": string; - ".git": string; - ".github": string; - ".gulp": string; - "bower_components": string; - "build": string; - "dist": string }; - "folderNamesExpanded": - { "node_modules": string; - ".git": string; - ".github": string; - ".gulp": string; - "bower_components": string; - "build": string; - "dist": string } } diff --git a/extensions/material.theme.config.ts b/extensions/material.theme.config.ts index 4382632..a1f5c40 100644 --- a/extensions/material.theme.config.ts +++ b/extensions/material.theme.config.ts @@ -3,10 +3,10 @@ import { commands as Commands } from 'vscode'; -import { THEME_ACCENTS_SETTER } from "./commands/accents-setter/index"; -import { THEME_ICONS } from "./commands/theme-icons/index"; -import { shouldShowChangelog, showChangelog } from './helpers/changelog'; -import { reloadWindow, getCurrentThemeID, setIconsID } from "./helpers/vscode"; +import {THEME_ACCENTS_SETTER} from './commands/accents-setter/index'; +import {THEME_ICONS} from './commands/theme-icons/index'; +import {shouldShowChangelog, showChangelog} from './helpers/changelog'; +import {reloadWindow, getCurrentThemeID, setIconsID} from './helpers/vscode'; const isMaterialTheme = (currentTheme: string): boolean => currentTheme.includes('Material Theme'); @@ -18,6 +18,7 @@ export function activate() { Workspace.onDidChangeConfiguration(event => { const isColorTheme = event.affectsConfiguration('workbench.colorTheme'); const currentTheme = getCurrentThemeID(); + // tslint:disable-next-line:early-exit if (isColorTheme && isMaterialTheme(currentTheme)) { setIconsID('eq-material-theme-icons') .then(() => THEME_ICONS().catch(error => console.trace(error))) diff --git a/gulpfile.babel.ts b/gulpfile.babel.ts index 40ab315..9cde7bd 100644 --- a/gulpfile.babel.ts +++ b/gulpfile.babel.ts @@ -6,4 +6,4 @@ import * as tasks from './.gulp'; GulpStats(Gulp); // set default task -Gulp.task('default', tasks.default as any); \ No newline at end of file +Gulp.task('default', tasks.default as any); diff --git a/package.json b/package.json index 3e647bb..a14a015 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "color": "#11131C", "theme": "dark" }, - "homepage": "https://github.com/equinusocio/vsc-material-theme", + "homepage": "https://equinsuocha.io/projects/material-theme/", "repository": { "type": "git", "url": "https://github.com/equinusocio/vsc-material-theme.git" @@ -38,6 +38,7 @@ "build-icons-variants": "yarn gulp build:icons.variants", "build-themes": "yarn gulp build:themes", "build-ts": "tsc -p ./tsconfig.json", + "test": "tslint **.ts", "release": "standard-version", "postinstall": "node ./node_modules/vscode/bin/install && opencollective postinstall && tsc -p tsconfig.json" }, @@ -46,16 +47,14 @@ "Other" ], "activationEvents": [ - "onCommand:materialTheme.setAccent", - "onCommand:materialTheme.fixIcons", - "onCommand:materialTheme.showChangelog" + "*" ], "main": "./extensions/material.theme.config.js", "contributes": { "commands": [ { "command": "materialTheme.setAccent", - "title": "Set the accent color", + "title": "Set accent color", "category": "🎨 Material Theme" }, { @@ -164,8 +163,6 @@ "babel-preset-es2015": "6.24.1", "babel-root-import": "4.1.8", "cpx": "1.5.0", - "eslint": "4.17.0", - "eslint-plugin-standard": "3.0.1", "gulp": "3.9.1", "gulp-bump": "3.1.0", "gulp-conventional-changelog": "1.1.11", @@ -179,7 +176,9 @@ "run-sequence": "2.2.1", "standard-version": "4.3.0", "svgo": "1.0.4", - "typescript": "2.7.1", + "tslint": "5.9.1", + "tslint-xo": "0.7.2", + "typescript": "2.8.3", "vscode": "1.1.10", "yamljs": "0.3.0", "yargs": "11.0.0" diff --git a/src/icons/partials/fileExtensions.js b/src/icons/partials/fileExtensions.js index 310421e..4ac7d9f 100644 --- a/src/icons/partials/fileExtensions.js +++ b/src/icons/partials/fileExtensions.js @@ -94,6 +94,7 @@ "ts": "_file_typescript", "tsx": "_file_react", "d.ts": "_file_typescript_def", + "spec.ts": "_file_typescript_def", "pdf": "_file_pdf", "xlsx": "_file_table", "xls": "_file_table", diff --git a/src/icons/svgs/git.svg b/src/icons/svgs/git.svg index 89a4c3c..79ae754 100755 --- a/src/icons/svgs/git.svg +++ b/src/icons/svgs/git.svg @@ -1,3 +1,3 @@ - + diff --git a/src/themes/theme-template-color-theme.json b/src/themes/theme-template-color-theme.json index 1c3f053..bdb9a8b 100644 --- a/src/themes/theme-template-color-theme.json +++ b/src/themes/theme-template-color-theme.json @@ -785,6 +785,8 @@ "editorError.foreground": "{{variant.scheme.base.red}}70", "editorWarning.foreground": "{{variant.scheme.base.green}}70", "editorWidget.background": "{{variant.scheme.backgroundAlt}}", + "editor.findWidgetResizeBorder": "{{commons.accents.Teal}}", + "editorWidget.border": "{{variant.scheme.base.Teal}}", "editorMarkerNavigation.background": "{{variant.scheme.foreground}}05", "widget.shadow": "{{variant.scheme.shadow}}", "panel.border": "{{variant.scheme.contrastBorder}}60", diff --git a/test/source.c b/test/source.c index f0094b3..644923c 100644 --- a/test/source.c +++ b/test/source.c @@ -58,1516 +58,3 @@ static inline int _ccv_run_bbf_feature(ccv_bbf_feature_t *feature, int *step, un #undef nf_at return 1; } - -static int _ccv_read_bbf_stage_classifier(const char *file, ccv_bbf_stage_classifier_t *classifier) -{ - FILE *r = fopen(file, "r"); - if (r == 0) - return -1; - int stat = 0; - stat |= fscanf(r, "%d", &classifier->count); - union { - float fl; - int i; - } fli; - stat |= fscanf(r, "%d", &fli.i); - classifier->threshold = fli.fl; - classifier->feature = (ccv_bbf_feature_t *)ccmalloc(classifier->count * sizeof(ccv_bbf_feature_t)); - classifier->alpha = (float *)ccmalloc(classifier->count * 2 * sizeof(float)); - int i, j; - for (i = 0; i < classifier->count; i++) - { - stat |= fscanf(r, "%d", &classifier->feature[i].size); - for (j = 0; j < classifier->feature[i].size; j++) - { - stat |= fscanf(r, "%d %d %d", &classifier->feature[i].px[j], &classifier->feature[i].py[j], &classifier->feature[i].pz[j]); - stat |= fscanf(r, "%d %d %d", &classifier->feature[i].nx[j], &classifier->feature[i].ny[j], &classifier->feature[i].nz[j]); - } - union { - float fl; - int i; - } flia, flib; - stat |= fscanf(r, "%d %d", &flia.i, &flib.i); - classifier->alpha[i * 2] = flia.fl; - classifier->alpha[i * 2 + 1] = flib.fl; - } - fclose(r); - return 0; -} - -#ifdef HAVE_GSL - -static unsigned int _ccv_bbf_time_measure() -{ - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec * 1000000 + tv.tv_usec; -} - -#define less_than(a, b, aux) ((a) < (b)) -CCV_IMPLEMENT_QSORT(_ccv_sort_32f, float, less_than) -#undef less_than - -static void _ccv_bbf_eval_data(ccv_bbf_stage_classifier_t *classifier, unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, ccv_size_t size, float *peval, float *neval) -{ - int i, j; - int steps[] = {_ccv_width_padding(size.width), - _ccv_width_padding(size.width >> 1), - _ccv_width_padding(size.width >> 2)}; - int isizs0 = steps[0] * size.height; - int isizs01 = isizs0 + steps[1] * (size.height >> 1); - for (i = 0; i < posnum; i++) - { - unsigned char *u8[] = {posdata[i], posdata[i] + isizs0, posdata[i] + isizs01}; - float sum = 0; - float *alpha = classifier->alpha; - ccv_bbf_feature_t *feature = classifier->feature; - for (j = 0; j < classifier->count; ++j, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - peval[i] = sum; - } - for (i = 0; i < negnum; i++) - { - unsigned char *u8[] = {negdata[i], negdata[i] + isizs0, negdata[i] + isizs01}; - float sum = 0; - float *alpha = classifier->alpha; - ccv_bbf_feature_t *feature = classifier->feature; - for (j = 0; j < classifier->count; ++j, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - neval[i] = sum; - } -} - -static int _ccv_prune_positive_data(ccv_bbf_classifier_cascade_t *cascade, unsigned char **posdata, int posnum, ccv_size_t size) -{ - float *peval = (float *)ccmalloc(posnum * sizeof(float)); - int i, j, k, rpos = posnum; - for (i = 0; i < cascade->count; i++) - { - _ccv_bbf_eval_data(cascade->stage_classifier + i, posdata, rpos, 0, 0, size, peval, 0); - k = 0; - for (j = 0; j < rpos; j++) - if (peval[j] >= cascade->stage_classifier[i].threshold) - { - posdata[k] = posdata[j]; - ++k; - } - else - { - ccfree(posdata[j]); - } - rpos = k; - } - ccfree(peval); - return rpos; -} - -static int _ccv_prepare_background_data(ccv_bbf_classifier_cascade_t *cascade, char **bgfiles, int bgnum, unsigned char **negdata, int negnum) -{ - int t, i, j, k, q; - int negperbg; - int negtotal = 0; - int steps[] = {_ccv_width_padding(cascade->size.width), - _ccv_width_padding(cascade->size.width >> 1), - _ccv_width_padding(cascade->size.width >> 2)}; - int isizs0 = steps[0] * cascade->size.height; - int isizs1 = steps[1] * (cascade->size.height >> 1); - int isizs2 = steps[2] * (cascade->size.height >> 2); - int *idcheck = (int *)ccmalloc(negnum * sizeof(int)); - - gsl_rng_env_setup(); - - gsl_rng *rng = gsl_rng_alloc(gsl_rng_default); - gsl_rng_set(rng, (unsigned long int)idcheck); - - ccv_size_t imgsz = cascade->size; - int rneg = negtotal; - for (t = 0; negtotal < negnum; t++) - { - PRINT(CCV_CLI_INFO, "preparing negative data ... 0%%"); - for (i = 0; i < bgnum; i++) - { - negperbg = (t < 2) ? (negnum - negtotal) / (bgnum - i) + 1 : negnum - negtotal; - ccv_dense_matrix_t *image = 0; - ccv_read(bgfiles[i], &image, CCV_IO_GRAY | CCV_IO_ANY_FILE); - assert((image->type & CCV_C1) && (image->type & CCV_8U)); - if (image == 0) - { - PRINT(CCV_CLI_ERROR, "\n%s file corrupted\n", bgfiles[i]); - continue; - } - if (t % 2 != 0) - ccv_flip(image, 0, 0, CCV_FLIP_X); - if (t % 4 >= 2) - ccv_flip(image, 0, 0, CCV_FLIP_Y); - ccv_bbf_param_t params = {.interval = 3, .min_neighbors = 0, .accurate = 1, .flags = 0, .size = cascade->size}; - ccv_array_t *detected = ccv_bbf_detect_objects(image, &cascade, 1, params); - memset(idcheck, 0, ccv_min(detected->rnum, negperbg) * sizeof(int)); - for (j = 0; j < ccv_min(detected->rnum, negperbg); j++) - { - int r = gsl_rng_uniform_int(rng, detected->rnum); - int flag = 1; - ccv_rect_t *rect = (ccv_rect_t *)ccv_array_get(detected, r); - while (flag) - { - flag = 0; - for (k = 0; k < j; k++) - if (r == idcheck[k]) - { - flag = 1; - r = gsl_rng_uniform_int(rng, detected->rnum); - break; - } - rect = (ccv_rect_t *)ccv_array_get(detected, r); - if ((rect->x < 0) || (rect->y < 0) || (rect->width + rect->x > image->cols) || (rect->height + rect->y > image->rows)) - { - flag = 1; - r = gsl_rng_uniform_int(rng, detected->rnum); - } - } - idcheck[j] = r; - ccv_dense_matrix_t *temp = 0; - ccv_dense_matrix_t *imgs0 = 0; - ccv_dense_matrix_t *imgs1 = 0; - ccv_dense_matrix_t *imgs2 = 0; - ccv_slice(image, (ccv_matrix_t **)&temp, 0, rect->y, rect->x, rect->height, rect->width); - ccv_resample(temp, &imgs0, 0, imgsz.height, imgsz.width, CCV_INTER_AREA); - assert(imgs0->step == steps[0]); - ccv_matrix_free(temp); - ccv_sample_down(imgs0, &imgs1, 0, 0, 0); - assert(imgs1->step == steps[1]); - ccv_sample_down(imgs1, &imgs2, 0, 0, 0); - assert(imgs2->step == steps[2]); - - negdata[negtotal] = (unsigned char *)ccmalloc(isizs0 + isizs1 + isizs2); - unsigned char *u8s0 = negdata[negtotal]; - unsigned char *u8s1 = negdata[negtotal] + isizs0; - unsigned char *u8s2 = negdata[negtotal] + isizs0 + isizs1; - unsigned char *u8[] = {u8s0, u8s1, u8s2}; - memcpy(u8s0, imgs0->data.u8, imgs0->rows * imgs0->step); - ccv_matrix_free(imgs0); - memcpy(u8s1, imgs1->data.u8, imgs1->rows * imgs1->step); - ccv_matrix_free(imgs1); - memcpy(u8s2, imgs2->data.u8, imgs2->rows * imgs2->step); - ccv_matrix_free(imgs2); - - flag = 1; - ccv_bbf_stage_classifier_t *classifier = cascade->stage_classifier; - for (k = 0; k < cascade->count; ++k, ++classifier) - { - float sum = 0; - float *alpha = classifier->alpha; - ccv_bbf_feature_t *feature = classifier->feature; - for (q = 0; q < classifier->count; ++q, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - if (sum < classifier->threshold) - { - flag = 0; - break; - } - } - if (!flag) - ccfree(negdata[negtotal]); - else - { - ++negtotal; - if (negtotal >= negnum) - break; - } - } - ccv_array_free(detected); - ccv_matrix_free(image); - ccv_drain_cache(); - PRINT(CCV_CLI_INFO, "\rpreparing negative data ... %2d%%", 100 * negtotal / negnum); - fflush(0); - if (negtotal >= negnum) - break; - } - if (rneg == negtotal) - break; - rneg = negtotal; - PRINT(CCV_CLI_INFO, "\nentering additional round %d\n", t + 1); - } - gsl_rng_free(rng); - ccfree(idcheck); - ccv_drain_cache(); - PRINT(CCV_CLI_INFO, "\n"); - return negtotal; -} - -static void _ccv_prepare_positive_data(ccv_dense_matrix_t **posimg, unsigned char **posdata, ccv_size_t size, int posnum) -{ - PRINT(CCV_CLI_INFO, "preparing positive data ... 0%%"); - int i; - for (i = 0; i < posnum; i++) - { - ccv_dense_matrix_t *imgs0 = posimg[i]; - ccv_dense_matrix_t *imgs1 = 0; - ccv_dense_matrix_t *imgs2 = 0; - assert((imgs0->type & CCV_C1) && (imgs0->type & CCV_8U) && imgs0->rows == size.height && imgs0->cols == size.width); - ccv_sample_down(imgs0, &imgs1, 0, 0, 0); - ccv_sample_down(imgs1, &imgs2, 0, 0, 0); - int isizs0 = imgs0->rows * imgs0->step; - int isizs1 = imgs1->rows * imgs1->step; - int isizs2 = imgs2->rows * imgs2->step; - - posdata[i] = (unsigned char *)ccmalloc(isizs0 + isizs1 + isizs2); - memcpy(posdata[i], imgs0->data.u8, isizs0); - memcpy(posdata[i] + isizs0, imgs1->data.u8, isizs1); - memcpy(posdata[i] + isizs0 + isizs1, imgs2->data.u8, isizs2); - - PRINT(CCV_CLI_INFO, "\rpreparing positive data ... %2d%%", 100 * (i + 1) / posnum); - fflush(0); - - ccv_matrix_free(imgs1); - ccv_matrix_free(imgs2); - } - ccv_drain_cache(); - PRINT(CCV_CLI_INFO, "\n"); -} - -typedef struct -{ - double fitness; - int pk, nk; - int age; - double error; - ccv_bbf_feature_t feature; -} ccv_bbf_gene_t; - -static inline void _ccv_bbf_genetic_fitness(ccv_bbf_gene_t *gene) -{ - gene->fitness = (1 - gene->error) * exp(-0.01 * gene->age) * exp((gene->pk + gene->nk) * log(1.015)); -} - -static inline int _ccv_bbf_exist_gene_feature(ccv_bbf_gene_t *gene, int x, int y, int z) -{ - int i; - for (i = 0; i < gene->pk; i++) - if (z == gene->feature.pz[i] && x == gene->feature.px[i] && y == gene->feature.py[i]) - return 1; - for (i = 0; i < gene->nk; i++) - if (z == gene->feature.nz[i] && x == gene->feature.nx[i] && y == gene->feature.ny[i]) - return 1; - return 0; -} - -static inline void _ccv_bbf_randomize_gene(gsl_rng *rng, ccv_bbf_gene_t *gene, int *rows, int *cols) -{ - int i; - do - { - gene->pk = gsl_rng_uniform_int(rng, CCV_BBF_POINT_MAX - 1) + 1; - gene->nk = gsl_rng_uniform_int(rng, CCV_BBF_POINT_MAX - 1) + 1; - } while (gene->pk + gene->nk < CCV_BBF_POINT_MIN); /* a hard restriction of at least 3 points have to be examed */ - gene->feature.size = ccv_max(gene->pk, gene->nk); - gene->age = 0; - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - { - gene->feature.pz[i] = -1; - gene->feature.nz[i] = -1; - } - int x, y, z; - for (i = 0; i < gene->pk; i++) - { - do - { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(gene, x, y, z)); - gene->feature.pz[i] = z; - gene->feature.px[i] = x; - gene->feature.py[i] = y; - } - for (i = 0; i < gene->nk; i++) - { - do - { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(gene, x, y, z)); - gene->feature.nz[i] = z; - gene->feature.nx[i] = x; - gene->feature.ny[i] = y; - } -} - -static inline double _ccv_bbf_error_rate(ccv_bbf_feature_t *feature, unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, ccv_size_t size, double *pw, double *nw) -{ - int i; - int steps[] = {_ccv_width_padding(size.width), - _ccv_width_padding(size.width >> 1), - _ccv_width_padding(size.width >> 2)}; - int isizs0 = steps[0] * size.height; - int isizs01 = isizs0 + steps[1] * (size.height >> 1); - double error = 0; - for (i = 0; i < posnum; i++) - { - unsigned char *u8[] = {posdata[i], posdata[i] + isizs0, posdata[i] + isizs01}; - if (!_ccv_run_bbf_feature(feature, steps, u8)) - error += pw[i]; - } - for (i = 0; i < negnum; i++) - { - unsigned char *u8[] = {negdata[i], negdata[i] + isizs0, negdata[i] + isizs01}; - if (_ccv_run_bbf_feature(feature, steps, u8)) - error += nw[i]; - } - return error; -} - -#define less_than(fit1, fit2, aux) ((fit1).fitness >= (fit2).fitness) -static CCV_IMPLEMENT_QSORT(_ccv_bbf_genetic_qsort, ccv_bbf_gene_t, less_than) -#undef less_than - - static ccv_bbf_feature_t _ccv_bbf_genetic_optimize(unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, int ftnum, ccv_size_t size, double *pw, double *nw) -{ - ccv_bbf_feature_t best; - /* seed (random method) */ - gsl_rng_env_setup(); - gsl_rng *rng = gsl_rng_alloc(gsl_rng_default); - union { - unsigned long int li; - double db; - } dbli; - dbli.db = pw[0] + nw[0]; - gsl_rng_set(rng, dbli.li); - int i, j; - int pnum = ftnum * 100; - assert(pnum > 0); - ccv_bbf_gene_t *gene = (ccv_bbf_gene_t *)ccmalloc(pnum * sizeof(ccv_bbf_gene_t)); - int rows[] = {size.height, size.height >> 1, size.height >> 2}; - int cols[] = {size.width, size.width >> 1, size.width >> 2}; - for (i = 0; i < pnum; i++) - _ccv_bbf_randomize_gene(rng, &gene[i], rows, cols); - unsigned int timer = _ccv_bbf_time_measure(); -#ifdef USE_OPENMP -#pragma omp parallel for private(i) schedule(dynamic) -#endif - for (i = 0; i < pnum; i++) - gene[i].error = _ccv_bbf_error_rate(&gene[i].feature, posdata, posnum, negdata, negnum, size, pw, nw); - timer = _ccv_bbf_time_measure() - timer; - for (i = 0; i < pnum; i++) - _ccv_bbf_genetic_fitness(&gene[i]); - double best_err = 1; - int rnum = ftnum * 39; /* number of randomize */ - int mnum = ftnum * 40; /* number of mutation */ - int hnum = ftnum * 20; /* number of hybrid */ - /* iteration stop crit : best no change in 40 iterations */ - int it = 0, t; - for (t = 0; it < 40; ++it, ++t) - { - int min_id = 0; - double min_err = gene[0].error; - for (i = 1; i < pnum; i++) - if (gene[i].error < min_err) - { - min_id = i; - min_err = gene[i].error; - } - min_err = gene[min_id].error = _ccv_bbf_error_rate(&gene[min_id].feature, posdata, posnum, negdata, negnum, size, pw, nw); - if (min_err < best_err) - { - best_err = min_err; - memcpy(&best, &gene[min_id].feature, sizeof(best)); - PRINT(CCV_CLI_INFO, "best bbf feature with error %f\n|-size: %d\n|-positive point: ", best_err, best.size); - for (i = 0; i < best.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", best.px[i], best.py[i], best.pz[i]); - PRINT(CCV_CLI_INFO, "\n|-negative point: "); - for (i = 0; i < best.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", best.nx[i], best.ny[i], best.nz[i]); - PRINT(CCV_CLI_INFO, "\n"); - it = 0; - } - PRINT(CCV_CLI_INFO, "minimum error achieved in round %d(%d) : %f with %d ms\n", t, it, min_err, timer / 1000); - _ccv_bbf_genetic_qsort(gene, pnum, 0); - for (i = 0; i < ftnum; i++) - ++gene[i].age; - for (i = ftnum; i < ftnum + mnum; i++) - { - int parent = gsl_rng_uniform_int(rng, ftnum); - memcpy(gene + i, gene + parent, sizeof(ccv_bbf_gene_t)); - /* three mutation strategy : 1. add, 2. remove, 3. refine */ - int pnm, pn = gsl_rng_uniform_int(rng, 2); - int *pnk[] = {&gene[i].pk, &gene[i].nk}; - int *pnx[] = {gene[i].feature.px, gene[i].feature.nx}; - int *pny[] = {gene[i].feature.py, gene[i].feature.ny}; - int *pnz[] = {gene[i].feature.pz, gene[i].feature.nz}; - int x, y, z; - int victim, decay = 1; - do - { - switch (gsl_rng_uniform_int(rng, 3)) - { - case 0: /* add */ - if (gene[i].pk == CCV_BBF_POINT_MAX && gene[i].nk == CCV_BBF_POINT_MAX) - break; - while (*pnk[pn] + 1 > CCV_BBF_POINT_MAX) - pn = gsl_rng_uniform_int(rng, 2); - do - { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(&gene[i], x, y, z)); - pnz[pn][*pnk[pn]] = z; - pnx[pn][*pnk[pn]] = x; - pny[pn][*pnk[pn]] = y; - ++(*pnk[pn]); - gene[i].feature.size = ccv_max(gene[i].pk, gene[i].nk); - decay = gene[i].age = 0; - break; - case 1: /* remove */ - if (gene[i].pk + gene[i].nk <= CCV_BBF_POINT_MIN) /* at least 3 points have to be examed */ - break; - while (*pnk[pn] - 1 <= 0) // || *pnk[pn] + *pnk[!pn] - 1 < CCV_BBF_POINT_MIN) - pn = gsl_rng_uniform_int(rng, 2); - victim = gsl_rng_uniform_int(rng, *pnk[pn]); - for (j = victim; j < *pnk[pn] - 1; j++) - { - pnz[pn][j] = pnz[pn][j + 1]; - pnx[pn][j] = pnx[pn][j + 1]; - pny[pn][j] = pny[pn][j + 1]; - } - pnz[pn][*pnk[pn] - 1] = -1; - --(*pnk[pn]); - gene[i].feature.size = ccv_max(gene[i].pk, gene[i].nk); - decay = gene[i].age = 0; - break; - case 2: /* refine */ - pnm = gsl_rng_uniform_int(rng, *pnk[pn]); - do - { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(&gene[i], x, y, z)); - pnz[pn][pnm] = z; - pnx[pn][pnm] = x; - pny[pn][pnm] = y; - decay = gene[i].age = 0; - break; - } - } while (decay); - } - for (i = ftnum + mnum; i < ftnum + mnum + hnum; i++) - { - /* hybrid strategy: taking positive points from dad, negative points from mum */ - int dad, mum; - do - { - dad = gsl_rng_uniform_int(rng, ftnum); - mum = gsl_rng_uniform_int(rng, ftnum); - } while (dad == mum || gene[dad].pk + gene[mum].nk < CCV_BBF_POINT_MIN); /* at least 3 points have to be examed */ - for (j = 0; j < CCV_BBF_POINT_MAX; j++) - { - gene[i].feature.pz[j] = -1; - gene[i].feature.nz[j] = -1; - } - gene[i].pk = gene[dad].pk; - for (j = 0; j < gene[i].pk; j++) - { - gene[i].feature.pz[j] = gene[dad].feature.pz[j]; - gene[i].feature.px[j] = gene[dad].feature.px[j]; - gene[i].feature.py[j] = gene[dad].feature.py[j]; - } - gene[i].nk = gene[mum].nk; - for (j = 0; j < gene[i].nk; j++) - { - gene[i].feature.nz[j] = gene[mum].feature.nz[j]; - gene[i].feature.nx[j] = gene[mum].feature.nx[j]; - gene[i].feature.ny[j] = gene[mum].feature.ny[j]; - } - gene[i].feature.size = ccv_max(gene[i].pk, gene[i].nk); - gene[i].age = 0; - } - for (i = ftnum + mnum + hnum; i < ftnum + mnum + hnum + rnum; i++) - _ccv_bbf_randomize_gene(rng, &gene[i], rows, cols); - timer = _ccv_bbf_time_measure(); -#ifdef USE_OPENMP -#pragma omp parallel for private(i) schedule(dynamic) -#endif - for (i = 0; i < pnum; i++) - gene[i].error = _ccv_bbf_error_rate(&gene[i].feature, posdata, posnum, negdata, negnum, size, pw, nw); - timer = _ccv_bbf_time_measure() - timer; - for (i = 0; i < pnum; i++) - _ccv_bbf_genetic_fitness(&gene[i]); - } - ccfree(gene); - gsl_rng_free(rng); - return best; -} - -#define less_than(fit1, fit2, aux) ((fit1).error < (fit2).error) -static CCV_IMPLEMENT_QSORT(_ccv_bbf_best_qsort, ccv_bbf_gene_t, less_than) -#undef less_than - - static ccv_bbf_gene_t _ccv_bbf_best_gene(ccv_bbf_gene_t *gene, int pnum, int point_min, unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, ccv_size_t size, double *pw, double *nw) -{ - int i; - unsigned int timer = _ccv_bbf_time_measure(); -#ifdef USE_OPENMP -#pragma omp parallel for private(i) schedule(dynamic) -#endif - for (i = 0; i < pnum; i++) - gene[i].error = _ccv_bbf_error_rate(&gene[i].feature, posdata, posnum, negdata, negnum, size, pw, nw); - timer = _ccv_bbf_time_measure() - timer; - _ccv_bbf_best_qsort(gene, pnum, 0); - int min_id = 0; - double min_err = gene[0].error; - for (i = 0; i < pnum; i++) - if (gene[i].nk + gene[i].pk >= point_min) - { - min_id = i; - min_err = gene[i].error; - break; - } - PRINT(CCV_CLI_INFO, "local best bbf feature with error %f\n|-size: %d\n|-positive point: ", min_err, gene[min_id].feature.size); - for (i = 0; i < gene[min_id].feature.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", gene[min_id].feature.px[i], gene[min_id].feature.py[i], gene[min_id].feature.pz[i]); - PRINT(CCV_CLI_INFO, "\n|-negative point: "); - for (i = 0; i < gene[min_id].feature.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", gene[min_id].feature.nx[i], gene[min_id].feature.ny[i], gene[min_id].feature.nz[i]); - PRINT(CCV_CLI_INFO, "\nthe computation takes %d ms\n", timer / 1000); - return gene[min_id]; -} - -static ccv_bbf_feature_t _ccv_bbf_convex_optimize(unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, ccv_bbf_feature_t *best_feature, ccv_size_t size, double *pw, double *nw) -{ - ccv_bbf_gene_t best_gene; - /* seed (random method) */ - gsl_rng_env_setup(); - gsl_rng *rng = gsl_rng_alloc(gsl_rng_default); - union { - unsigned long int li; - double db; - } dbli; - dbli.db = pw[0] + nw[0]; - gsl_rng_set(rng, dbli.li); - int i, j, k, q, p, g, t; - int rows[] = {size.height, size.height >> 1, size.height >> 2}; - int cols[] = {size.width, size.width >> 1, size.width >> 2}; - int pnum = rows[0] * cols[0] + rows[1] * cols[1] + rows[2] * cols[2]; - ccv_bbf_gene_t *gene = (ccv_bbf_gene_t *)ccmalloc((pnum * (CCV_BBF_POINT_MAX * 2 + 1) * 2 + CCV_BBF_POINT_MAX * 2 + 1) * sizeof(ccv_bbf_gene_t)); - if (best_feature == 0) - { - /* bootstrapping the best feature, start from two pixels, one for positive, one for negative - * the bootstrapping process go like this: first, it will assign a random pixel as positive - * and enumerate every possible pixel as negative, and pick the best one. Then, enumerate every - * possible pixel as positive, and pick the best one, until it converges */ - memset(&best_gene, 0, sizeof(ccv_bbf_gene_t)); - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - best_gene.feature.pz[i] = best_gene.feature.nz[i] = -1; - best_gene.pk = 1; - best_gene.nk = 0; - best_gene.feature.size = 1; - best_gene.feature.pz[0] = gsl_rng_uniform_int(rng, 3); - best_gene.feature.px[0] = gsl_rng_uniform_int(rng, cols[best_gene.feature.pz[0]]); - best_gene.feature.py[0] = gsl_rng_uniform_int(rng, rows[best_gene.feature.pz[0]]); - for (t = 0;; ++t) - { - g = 0; - if (t % 2 == 0) - { - for (i = 0; i < 3; i++) - for (j = 0; j < cols[i]; j++) - for (k = 0; k < rows[i]; k++) - if (i != best_gene.feature.pz[0] || j != best_gene.feature.px[0] || k != best_gene.feature.py[0]) - { - gene[g] = best_gene; - gene[g].pk = gene[g].nk = 1; - gene[g].feature.nz[0] = i; - gene[g].feature.nx[0] = j; - gene[g].feature.ny[0] = k; - g++; - } - } - else - { - for (i = 0; i < 3; i++) - for (j = 0; j < cols[i]; j++) - for (k = 0; k < rows[i]; k++) - if (i != best_gene.feature.nz[0] || j != best_gene.feature.nx[0] || k != best_gene.feature.ny[0]) - { - gene[g] = best_gene; - gene[g].pk = gene[g].nk = 1; - gene[g].feature.pz[0] = i; - gene[g].feature.px[0] = j; - gene[g].feature.py[0] = k; - g++; - } - } - PRINT(CCV_CLI_INFO, "bootstrapping round : %d\n", t); - ccv_bbf_gene_t local_gene = _ccv_bbf_best_gene(gene, g, 2, posdata, posnum, negdata, negnum, size, pw, nw); - if (local_gene.error >= best_gene.error - 1e-10) - break; - best_gene = local_gene; - } - } - else - { - best_gene.feature = *best_feature; - best_gene.pk = best_gene.nk = best_gene.feature.size; - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - if (best_feature->pz[i] == -1) - { - best_gene.pk = i; - break; - } - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - if (best_feature->nz[i] == -1) - { - best_gene.nk = i; - break; - } - } - /* after bootstrapping, the float search technique will do the following permutations: - * a). add a new point to positive or negative - * b). remove a point from positive or negative - * c). move an existing point in positive or negative to another position - * the three rules applied exhaustively, no heuristic used. */ - for (t = 0;; ++t) - { - g = 0; - for (i = 0; i < 3; i++) - for (j = 0; j < cols[i]; j++) - for (k = 0; k < rows[i]; k++) - if (!_ccv_bbf_exist_gene_feature(&best_gene, j, k, i)) - { - /* add positive point */ - if (best_gene.pk < CCV_BBF_POINT_MAX - 1) - { - gene[g] = best_gene; - gene[g].feature.pz[gene[g].pk] = i; - gene[g].feature.px[gene[g].pk] = j; - gene[g].feature.py[gene[g].pk] = k; - gene[g].pk++; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - /* add negative point */ - if (best_gene.nk < CCV_BBF_POINT_MAX - 1) - { - gene[g] = best_gene; - gene[g].feature.nz[gene[g].nk] = i; - gene[g].feature.nx[gene[g].nk] = j; - gene[g].feature.ny[gene[g].nk] = k; - gene[g].nk++; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - /* refine positive point */ - for (q = 0; q < best_gene.pk; q++) - { - gene[g] = best_gene; - gene[g].feature.pz[q] = i; - gene[g].feature.px[q] = j; - gene[g].feature.py[q] = k; - g++; - } - /* add positive point, remove negative point */ - if (best_gene.pk < CCV_BBF_POINT_MAX - 1 && best_gene.nk > 1) - { - for (q = 0; q < best_gene.nk; q++) - { - gene[g] = best_gene; - gene[g].feature.pz[gene[g].pk] = i; - gene[g].feature.px[gene[g].pk] = j; - gene[g].feature.py[gene[g].pk] = k; - gene[g].pk++; - for (p = q; p < best_gene.nk - 1; p++) - { - gene[g].feature.nz[p] = gene[g].feature.nz[p + 1]; - gene[g].feature.nx[p] = gene[g].feature.nx[p + 1]; - gene[g].feature.ny[p] = gene[g].feature.ny[p + 1]; - } - gene[g].feature.nz[gene[g].nk - 1] = -1; - gene[g].nk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - } - /* refine negative point */ - for (q = 0; q < best_gene.nk; q++) - { - gene[g] = best_gene; - gene[g].feature.nz[q] = i; - gene[g].feature.nx[q] = j; - gene[g].feature.ny[q] = k; - g++; - } - /* add negative point, remove positive point */ - if (best_gene.pk > 1 && best_gene.nk < CCV_BBF_POINT_MAX - 1) - { - for (q = 0; q < best_gene.pk; q++) - { - gene[g] = best_gene; - gene[g].feature.nz[gene[g].nk] = i; - gene[g].feature.nx[gene[g].nk] = j; - gene[g].feature.ny[gene[g].nk] = k; - gene[g].nk++; - for (p = q; p < best_gene.pk - 1; p++) - { - gene[g].feature.pz[p] = gene[g].feature.pz[p + 1]; - gene[g].feature.px[p] = gene[g].feature.px[p + 1]; - gene[g].feature.py[p] = gene[g].feature.py[p + 1]; - } - gene[g].feature.pz[gene[g].pk - 1] = -1; - gene[g].pk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - } - } - if (best_gene.pk > 1) - for (q = 0; q < best_gene.pk; q++) - { - gene[g] = best_gene; - for (i = q; i < best_gene.pk - 1; i++) - { - gene[g].feature.pz[i] = gene[g].feature.pz[i + 1]; - gene[g].feature.px[i] = gene[g].feature.px[i + 1]; - gene[g].feature.py[i] = gene[g].feature.py[i + 1]; - } - gene[g].feature.pz[gene[g].pk - 1] = -1; - gene[g].pk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - if (best_gene.nk > 1) - for (q = 0; q < best_gene.nk; q++) - { - gene[g] = best_gene; - for (i = q; i < best_gene.nk - 1; i++) - { - gene[g].feature.nz[i] = gene[g].feature.nz[i + 1]; - gene[g].feature.nx[i] = gene[g].feature.nx[i + 1]; - gene[g].feature.ny[i] = gene[g].feature.ny[i + 1]; - } - gene[g].feature.nz[gene[g].nk - 1] = -1; - gene[g].nk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - gene[g] = best_gene; - g++; - PRINT(CCV_CLI_INFO, "float search round : %d\n", t); - ccv_bbf_gene_t local_gene = _ccv_bbf_best_gene(gene, g, CCV_BBF_POINT_MIN, posdata, posnum, negdata, negnum, size, pw, nw); - if (local_gene.error >= best_gene.error - 1e-10) - break; - best_gene = local_gene; - } - ccfree(gene); - gsl_rng_free(rng); - return best_gene.feature; -} - -static int _ccv_write_bbf_stage_classifier(const char *file, ccv_bbf_stage_classifier_t *classifier) -{ - FILE *w = fopen(file, "wb"); - if (w == 0) - return -1; - fprintf(w, "%d\n", classifier->count); - union { - float fl; - int i; - } fli; - fli.fl = classifier->threshold; - fprintf(w, "%d\n", fli.i); - int i, j; - for (i = 0; i < classifier->count; i++) - { - fprintf(w, "%d\n", classifier->feature[i].size); - for (j = 0; j < classifier->feature[i].size; j++) - { - fprintf(w, "%d %d %d\n", classifier->feature[i].px[j], classifier->feature[i].py[j], classifier->feature[i].pz[j]); - fprintf(w, "%d %d %d\n", classifier->feature[i].nx[j], classifier->feature[i].ny[j], classifier->feature[i].nz[j]); - } - union { - float fl; - int i; - } flia, flib; - flia.fl = classifier->alpha[i * 2]; - flib.fl = classifier->alpha[i * 2 + 1]; - fprintf(w, "%d %d\n", flia.i, flib.i); - } - fclose(w); - return 0; -} - -static int _ccv_read_background_data(const char *file, unsigned char **negdata, int *negnum, ccv_size_t size) -{ - int stat = 0; - FILE *r = fopen(file, "rb"); - if (r == 0) - return -1; - stat |= fread(negnum, sizeof(int), 1, r); - int i; - int isizs012 = _ccv_width_padding(size.width) * size.height + - _ccv_width_padding(size.width >> 1) * (size.height >> 1) + - _ccv_width_padding(size.width >> 2) * (size.height >> 2); - for (i = 0; i < *negnum; i++) - { - negdata[i] = (unsigned char *)ccmalloc(isizs012); - stat |= fread(negdata[i], 1, isizs012, r); - } - fclose(r); - return 0; -} - -static int _ccv_write_background_data(const char *file, unsigned char **negdata, int negnum, ccv_size_t size) -{ - FILE *w = fopen(file, "w"); - if (w == 0) - return -1; - fwrite(&negnum, sizeof(int), 1, w); - int i; - int isizs012 = _ccv_width_padding(size.width) * size.height + - _ccv_width_padding(size.width >> 1) * (size.height >> 1) + - _ccv_width_padding(size.width >> 2) * (size.height >> 2); - for (i = 0; i < negnum; i++) - fwrite(negdata[i], 1, isizs012, w); - fclose(w); - return 0; -} - -static int _ccv_resume_bbf_cascade_training_state(const char *file, int *i, int *k, int *bg, double *pw, double *nw, int posnum, int negnum) -{ - int stat = 0; - FILE *r = fopen(file, "r"); - if (r == 0) - return -1; - stat |= fscanf(r, "%d %d %d", i, k, bg); - int j; - union { - double db; - int i[2]; - } dbi; - for (j = 0; j < posnum; j++) - { - stat |= fscanf(r, "%d %d", &dbi.i[0], &dbi.i[1]); - pw[j] = dbi.db; - } - for (j = 0; j < negnum; j++) - { - stat |= fscanf(r, "%d %d", &dbi.i[0], &dbi.i[1]); - nw[j] = dbi.db; - } - fclose(r); - return 0; -} - -static int _ccv_save_bbf_cacade_training_state(const char *file, int i, int k, int bg, double *pw, double *nw, int posnum, int negnum) -{ - FILE *w = fopen(file, "w"); - if (w == 0) - return -1; - fprintf(w, "%d %d %d\n", i, k, bg); - int j; - union { - double db; - int i[2]; - } dbi; - for (j = 0; j < posnum; ++j) - { - dbi.db = pw[j]; - fprintf(w, "%d %d ", dbi.i[0], dbi.i[1]); - } - fprintf(w, "\n"); - for (j = 0; j < negnum; ++j) - { - dbi.db = nw[j]; - fprintf(w, "%d %d ", dbi.i[0], dbi.i[1]); - } - fprintf(w, "\n"); - fclose(w); - return 0; -} - -void ccv_bbf_classifier_cascade_new(ccv_dense_matrix_t **posimg, int posnum, char **bgfiles, int bgnum, int negnum, ccv_size_t size, const char *dir, ccv_bbf_new_param_t params) -{ - int i, j, k; - /* allocate memory for usage */ - ccv_bbf_classifier_cascade_t *cascade = (ccv_bbf_classifier_cascade_t *)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); - cascade->count = 0; - cascade->size = size; - cascade->stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(sizeof(ccv_bbf_stage_classifier_t)); - unsigned char **posdata = (unsigned char **)ccmalloc(posnum * sizeof(unsigned char *)); - unsigned char **negdata = (unsigned char **)ccmalloc(negnum * sizeof(unsigned char *)); - double *pw = (double *)ccmalloc(posnum * sizeof(double)); - double *nw = (double *)ccmalloc(negnum * sizeof(double)); - float *peval = (float *)ccmalloc(posnum * sizeof(float)); - float *neval = (float *)ccmalloc(negnum * sizeof(float)); - double inv_balance_k = 1. / params.balance_k; - /* balance factor k, and weighted with 0.01 */ - params.balance_k *= 0.01; - inv_balance_k *= 0.01; - - int steps[] = {_ccv_width_padding(cascade->size.width), - _ccv_width_padding(cascade->size.width >> 1), - _ccv_width_padding(cascade->size.width >> 2)}; - int isizs0 = steps[0] * cascade->size.height; - int isizs01 = isizs0 + steps[1] * (cascade->size.height >> 1); - - i = 0; - k = 0; - int bg = 0; - int cacheK = 10; - /* state resume code */ - char buf[1024]; - sprintf(buf, "%s/stat.txt", dir); - _ccv_resume_bbf_cascade_training_state(buf, &i, &k, &bg, pw, nw, posnum, negnum); - if (i > 0) - { - cascade->count = i; - ccfree(cascade->stage_classifier); - cascade->stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(i * sizeof(ccv_bbf_stage_classifier_t)); - for (j = 0; j < i; j++) - { - sprintf(buf, "%s/stage-%d.txt", dir, j); - _ccv_read_bbf_stage_classifier(buf, &cascade->stage_classifier[j]); - } - } - if (k > 0) - cacheK = k; - int rpos, rneg = 0; - if (bg) - { - sprintf(buf, "%s/negs.txt", dir); - _ccv_read_background_data(buf, negdata, &rneg, cascade->size); - } - - for (; i < params.layer; i++) - { - if (!bg) - { - rneg = _ccv_prepare_background_data(cascade, bgfiles, bgnum, negdata, negnum); - /* save state of background data */ - sprintf(buf, "%s/negs.txt", dir); - _ccv_write_background_data(buf, negdata, rneg, cascade->size); - bg = 1; - } - double totalw; - /* save state of cascade : level, weight etc. */ - sprintf(buf, "%s/stat.txt", dir); - _ccv_save_bbf_cacade_training_state(buf, i, k, bg, pw, nw, posnum, negnum); - ccv_bbf_stage_classifier_t classifier; - if (k > 0) - { - /* resume state of classifier */ - sprintf(buf, "%s/stage-%d.txt", dir, i); - _ccv_read_bbf_stage_classifier(buf, &classifier); - } - else - { - /* initialize classifier */ - for (j = 0; j < posnum; j++) - pw[j] = params.balance_k; - for (j = 0; j < rneg; j++) - nw[j] = inv_balance_k; - classifier.count = k; - classifier.threshold = 0; - classifier.feature = (ccv_bbf_feature_t *)ccmalloc(cacheK * sizeof(ccv_bbf_feature_t)); - classifier.alpha = (float *)ccmalloc(cacheK * 2 * sizeof(float)); - } - _ccv_prepare_positive_data(posimg, posdata, cascade->size, posnum); - rpos = _ccv_prune_positive_data(cascade, posdata, posnum, cascade->size); - PRINT(CCV_CLI_INFO, "%d postivie data and %d negative data in training\n", rpos, rneg); - /* reweight to 1.00 */ - totalw = 0; - for (j = 0; j < rpos; j++) - totalw += pw[j]; - for (j = 0; j < rneg; j++) - totalw += nw[j]; - for (j = 0; j < rpos; j++) - pw[j] = pw[j] / totalw; - for (j = 0; j < rneg; j++) - nw[j] = nw[j] / totalw; - for (;; k++) - { - /* get overall true-positive, false-positive rate and threshold */ - double tp = 0, fp = 0, etp = 0, efp = 0; - _ccv_bbf_eval_data(&classifier, posdata, rpos, negdata, rneg, cascade->size, peval, neval); - _ccv_sort_32f(peval, rpos, 0); - classifier.threshold = peval[(int)((1. - params.pos_crit) * rpos)] - 1e-6; - for (j = 0; j < rpos; j++) - { - if (peval[j] >= 0) - ++tp; - if (peval[j] >= classifier.threshold) - ++etp; - } - tp /= rpos; - etp /= rpos; - for (j = 0; j < rneg; j++) - { - if (neval[j] >= 0) - ++fp; - if (neval[j] >= classifier.threshold) - ++efp; - } - fp /= rneg; - efp /= rneg; - PRINT(CCV_CLI_INFO, "stage classifier real TP rate : %f, FP rate : %f\n", tp, fp); - PRINT(CCV_CLI_INFO, "stage classifier TP rate : %f, FP rate : %f at threshold : %f\n", etp, efp, classifier.threshold); - if (k > 0) - { - /* save classifier state */ - sprintf(buf, "%s/stage-%d.txt", dir, i); - _ccv_write_bbf_stage_classifier(buf, &classifier); - sprintf(buf, "%s/stat.txt", dir); - _ccv_save_bbf_cacade_training_state(buf, i, k, bg, pw, nw, posnum, negnum); - } - if (etp > params.pos_crit && efp < params.neg_crit) - break; - /* TODO: more post-process is needed in here */ - - /* select the best feature in current distribution through genetic algorithm optimization */ - ccv_bbf_feature_t best; - if (params.optimizer == CCV_BBF_GENETIC_OPT) - { - best = _ccv_bbf_genetic_optimize(posdata, rpos, negdata, rneg, params.feature_number, cascade->size, pw, nw); - } - else if (params.optimizer == CCV_BBF_FLOAT_OPT) - { - best = _ccv_bbf_convex_optimize(posdata, rpos, negdata, rneg, 0, cascade->size, pw, nw); - } - else - { - best = _ccv_bbf_genetic_optimize(posdata, rpos, negdata, rneg, params.feature_number, cascade->size, pw, nw); - best = _ccv_bbf_convex_optimize(posdata, rpos, negdata, rneg, &best, cascade->size, pw, nw); - } - double err = _ccv_bbf_error_rate(&best, posdata, rpos, negdata, rneg, cascade->size, pw, nw); - double rw = (1 - err) / err; - totalw = 0; - /* reweight */ - for (j = 0; j < rpos; j++) - { - unsigned char *u8[] = {posdata[j], posdata[j] + isizs0, posdata[j] + isizs01}; - if (!_ccv_run_bbf_feature(&best, steps, u8)) - pw[j] *= rw; - pw[j] *= params.balance_k; - totalw += pw[j]; - } - for (j = 0; j < rneg; j++) - { - unsigned char *u8[] = {negdata[j], negdata[j] + isizs0, negdata[j] + isizs01}; - if (_ccv_run_bbf_feature(&best, steps, u8)) - nw[j] *= rw; - nw[j] *= inv_balance_k; - totalw += nw[j]; - } - for (j = 0; j < rpos; j++) - pw[j] = pw[j] / totalw; - for (j = 0; j < rneg; j++) - nw[j] = nw[j] / totalw; - double c = log(rw); - PRINT(CCV_CLI_INFO, "coefficient of feature %d: %f\n", k + 1, c); - classifier.count = k + 1; - /* resizing classifier */ - if (k >= cacheK) - { - ccv_bbf_feature_t *feature = (ccv_bbf_feature_t *)ccmalloc(cacheK * 2 * sizeof(ccv_bbf_feature_t)); - memcpy(feature, classifier.feature, cacheK * sizeof(ccv_bbf_feature_t)); - ccfree(classifier.feature); - float *alpha = (float *)ccmalloc(cacheK * 4 * sizeof(float)); - memcpy(alpha, classifier.alpha, cacheK * 2 * sizeof(float)); - ccfree(classifier.alpha); - classifier.feature = feature; - classifier.alpha = alpha; - cacheK *= 2; - } - /* setup new feature */ - classifier.feature[k] = best; - classifier.alpha[k * 2] = -c; - classifier.alpha[k * 2 + 1] = c; - } - cascade->count = i + 1; - ccv_bbf_stage_classifier_t *stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(cascade->count * sizeof(ccv_bbf_stage_classifier_t)); - memcpy(stage_classifier, cascade->stage_classifier, i * sizeof(ccv_bbf_stage_classifier_t)); - ccfree(cascade->stage_classifier); - stage_classifier[i] = classifier; - cascade->stage_classifier = stage_classifier; - k = 0; - bg = 0; - for (j = 0; j < rpos; j++) - ccfree(posdata[j]); - for (j = 0; j < rneg; j++) - ccfree(negdata[j]); - } - - ccfree(neval); - ccfree(peval); - ccfree(nw); - ccfree(pw); - ccfree(negdata); - ccfree(posdata); - ccfree(cascade); -} -#else -void ccv_bbf_classifier_cascade_new(ccv_dense_matrix_t **posimg, int posnum, char **bgfiles, int bgnum, int negnum, ccv_size_t size, const char *dir, ccv_bbf_new_param_t params) -{ - fprintf(stderr, " ccv_bbf_classifier_cascade_new requires libgsl support, please compile ccv with libgsl.\n"); -} -#endif - -static int _ccv_is_equal(const void *_r1, const void *_r2, void *data) -{ - const ccv_comp_t *r1 = (const ccv_comp_t *)_r1; - const ccv_comp_t *r2 = (const ccv_comp_t *)_r2; - int distance = (int)(r1->rect.width * 0.25 + 0.5); - - return r2->rect.x <= r1->rect.x + distance && - r2->rect.x >= r1->rect.x - distance && - r2->rect.y <= r1->rect.y + distance && - r2->rect.y >= r1->rect.y - distance && - r2->rect.width <= (int)(r1->rect.width * 1.5 + 0.5) && - (int)(r2->rect.width * 1.5 + 0.5) >= r1->rect.width; -} - -static int _ccv_is_equal_same_class(const void *_r1, const void *_r2, void *data) -{ - const ccv_comp_t *r1 = (const ccv_comp_t *)_r1; - const ccv_comp_t *r2 = (const ccv_comp_t *)_r2; - int distance = (int)(r1->rect.width * 0.25 + 0.5); - - return r2->classification.id == r1->classification.id && - r2->rect.x <= r1->rect.x + distance && - r2->rect.x >= r1->rect.x - distance && - r2->rect.y <= r1->rect.y + distance && - r2->rect.y >= r1->rect.y - distance && - r2->rect.width <= (int)(r1->rect.width * 1.5 + 0.5) && - (int)(r2->rect.width * 1.5 + 0.5) >= r1->rect.width; -} - -ccv_array_t *ccv_bbf_detect_objects(ccv_dense_matrix_t *a, ccv_bbf_classifier_cascade_t **_cascade, int count, ccv_bbf_param_t params) -{ - int hr = a->rows / params.size.height; - int wr = a->cols / params.size.width; - double scale = pow(2., 1. / (params.interval + 1.)); - int next = params.interval + 1; - int scale_upto = (int)(log((double)ccv_min(hr, wr)) / log(scale)); - ccv_dense_matrix_t **pyr = (ccv_dense_matrix_t **)alloca((scale_upto + next * 2) * 4 * sizeof(ccv_dense_matrix_t *)); - memset(pyr, 0, (scale_upto + next * 2) * 4 * sizeof(ccv_dense_matrix_t *)); - if (params.size.height != _cascade[0]->size.height || params.size.width != _cascade[0]->size.width) - ccv_resample(a, &pyr[0], 0, a->rows * _cascade[0]->size.height / params.size.height, a->cols * _cascade[0]->size.width / params.size.width, CCV_INTER_AREA); - else - pyr[0] = a; - int i, j, k, t, x, y, q; - for (i = 1; i < ccv_min(params.interval + 1, scale_upto + next * 2); i++) - ccv_resample(pyr[0], &pyr[i * 4], 0, (int)(pyr[0]->rows / pow(scale, i)), (int)(pyr[0]->cols / pow(scale, i)), CCV_INTER_AREA); - for (i = next; i < scale_upto + next * 2; i++) - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4], 0, 0, 0); - if (params.accurate) - for (i = next * 2; i < scale_upto + next * 2; i++) - { - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 1], 0, 1, 0); - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 2], 0, 0, 1); - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 3], 0, 1, 1); - } - ccv_array_t *idx_seq; - ccv_array_t *seq = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - ccv_array_t *seq2 = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - ccv_array_t *result_seq = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - /* detect in multi scale */ - for (t = 0; t < count; t++) - { - ccv_bbf_classifier_cascade_t *cascade = _cascade[t]; - float scale_x = (float)params.size.width / (float)cascade->size.width; - float scale_y = (float)params.size.height / (float)cascade->size.height; - ccv_array_clear(seq); - for (i = 0; i < scale_upto; i++) - { - int dx[] = {0, 1, 0, 1}; - int dy[] = {0, 0, 1, 1}; - int i_rows = pyr[i * 4 + next * 8]->rows - (cascade->size.height >> 2); - int steps[] = {pyr[i * 4]->step, pyr[i * 4 + next * 4]->step, pyr[i * 4 + next * 8]->step}; - int i_cols = pyr[i * 4 + next * 8]->cols - (cascade->size.width >> 2); - int paddings[] = {pyr[i * 4]->step * 4 - i_cols * 4, - pyr[i * 4 + next * 4]->step * 2 - i_cols * 2, - pyr[i * 4 + next * 8]->step - i_cols}; - for (q = 0; q < (params.accurate ? 4 : 1); q++) - { - unsigned char *u8[] = {pyr[i * 4]->data.u8 + dx[q] * 2 + dy[q] * pyr[i * 4]->step * 2, pyr[i * 4 + next * 4]->data.u8 + dx[q] + dy[q] * pyr[i * 4 + next * 4]->step, pyr[i * 4 + next * 8 + q]->data.u8}; - for (y = 0; y < i_rows; y++) - { - for (x = 0; x < i_cols; x++) - { - float sum; - int flag = 1; - ccv_bbf_stage_classifier_t *classifier = cascade->stage_classifier; - for (j = 0; j < cascade->count; ++j, ++classifier) - { - sum = 0; - float *alpha = classifier->alpha; - ccv_bbf_feature_t *feature = classifier->feature; - for (k = 0; k < classifier->count; ++k, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - if (sum < classifier->threshold) - { - flag = 0; - break; - } - } - if (flag) - { - ccv_comp_t comp; - comp.rect = ccv_rect((int)((x * 4 + dx[q] * 2) * scale_x + 0.5), (int)((y * 4 + dy[q] * 2) * scale_y + 0.5), (int)(cascade->size.width * scale_x + 0.5), (int)(cascade->size.height * scale_y + 0.5)); - comp.neighbors = 1; - comp.classification.id = t; - comp.classification.confidence = sum; - ccv_array_push(seq, &comp); - } - u8[0] += 4; - u8[1] += 2; - u8[2] += 1; - } - u8[0] += paddings[0]; - u8[1] += paddings[1]; - u8[2] += paddings[2]; - } - } - scale_x *= scale; - scale_y *= scale; - } - - /* the following code from OpenCV's haar feature implementation */ - if (params.min_neighbors == 0) - { - for (i = 0; i < seq->rnum; i++) - { - ccv_comp_t *comp = (ccv_comp_t *)ccv_array_get(seq, i); - ccv_array_push(result_seq, comp); - } - } - else - { - idx_seq = 0; - ccv_array_clear(seq2); - // group retrieved rectangles in order to filter out noise - int ncomp = ccv_array_group(seq, &idx_seq, _ccv_is_equal_same_class, 0); - ccv_comp_t *comps = (ccv_comp_t *)ccmalloc((ncomp + 1) * sizeof(ccv_comp_t)); - memset(comps, 0, (ncomp + 1) * sizeof(ccv_comp_t)); - - // count number of neighbors - for (i = 0; i < seq->rnum; i++) - { - ccv_comp_t r1 = *(ccv_comp_t *)ccv_array_get(seq, i); - int idx = *(int *)ccv_array_get(idx_seq, i); - - if (comps[idx].neighbors == 0) - comps[idx].classification.confidence = r1.classification.confidence; - - ++comps[idx].neighbors; - - comps[idx].rect.x += r1.rect.x; - comps[idx].rect.y += r1.rect.y; - comps[idx].rect.width += r1.rect.width; - comps[idx].rect.height += r1.rect.height; - comps[idx].classification.id = r1.classification.id; - comps[idx].classification.confidence = ccv_max(comps[idx].classification.confidence, r1.classification.confidence); - } - - // calculate average bounding box - for (i = 0; i < ncomp; i++) - { - int n = comps[i].neighbors; - if (n >= params.min_neighbors) - { - ccv_comp_t comp; - comp.rect.x = (comps[i].rect.x * 2 + n) / (2 * n); - comp.rect.y = (comps[i].rect.y * 2 + n) / (2 * n); - comp.rect.width = (comps[i].rect.width * 2 + n) / (2 * n); - comp.rect.height = (comps[i].rect.height * 2 + n) / (2 * n); - comp.neighbors = comps[i].neighbors; - comp.classification.id = comps[i].classification.id; - comp.classification.confidence = comps[i].classification.confidence; - ccv_array_push(seq2, &comp); - } - } - - // filter out small face rectangles inside large face rectangles - for (i = 0; i < seq2->rnum; i++) - { - ccv_comp_t r1 = *(ccv_comp_t *)ccv_array_get(seq2, i); - int flag = 1; - - for (j = 0; j < seq2->rnum; j++) - { - ccv_comp_t r2 = *(ccv_comp_t *)ccv_array_get(seq2, j); - int distance = (int)(r2.rect.width * 0.25 + 0.5); - - if (i != j && - r1.classification.id == r2.classification.id && - r1.rect.x >= r2.rect.x - distance && - r1.rect.y >= r2.rect.y - distance && - r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance && - r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance && - (r2.neighbors > ccv_max(3, r1.neighbors) || r1.neighbors < 3)) - { - flag = 0; - break; - } - } - - if (flag) - ccv_array_push(result_seq, &r1); - } - ccv_array_free(idx_seq); - ccfree(comps); - } - } - - ccv_array_free(seq); - ccv_array_free(seq2); - - ccv_array_t *result_seq2; - /* the following code from OpenCV's haar feature implementation */ - if (params.flags & CCV_BBF_NO_NESTED) - { - result_seq2 = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - idx_seq = 0; - // group retrieved rectangles in order to filter out noise - int ncomp = ccv_array_group(result_seq, &idx_seq, _ccv_is_equal, 0); - ccv_comp_t *comps = (ccv_comp_t *)ccmalloc((ncomp + 1) * sizeof(ccv_comp_t)); - memset(comps, 0, (ncomp + 1) * sizeof(ccv_comp_t)); - - // count number of neighbors - for (i = 0; i < result_seq->rnum; i++) - { - ccv_comp_t r1 = *(ccv_comp_t *)ccv_array_get(result_seq, i); - int idx = *(int *)ccv_array_get(idx_seq, i); - - if (comps[idx].neighbors == 0 || comps[idx].classification.confidence < r1.classification.confidence) - { - comps[idx].classification.confidence = r1.classification.confidence; - comps[idx].neighbors = 1; - comps[idx].rect = r1.rect; - comps[idx].classification.id = r1.classification.id; - } - } - - // calculate average bounding box - for (i = 0; i < ncomp; i++) - if (comps[i].neighbors) - ccv_array_push(result_seq2, &comps[i]); - - ccv_array_free(result_seq); - ccfree(comps); - } - else - { - result_seq2 = result_seq; - } - - for (i = 1; i < scale_upto + next * 2; i++) - ccv_matrix_free(pyr[i * 4]); - if (params.accurate) - for (i = next * 2; i < scale_upto + next * 2; i++) - { - ccv_matrix_free(pyr[i * 4 + 1]); - ccv_matrix_free(pyr[i * 4 + 2]); - ccv_matrix_free(pyr[i * 4 + 3]); - } - if (params.size.height != _cascade[0]->size.height || params.size.width != _cascade[0]->size.width) - ccv_matrix_free(pyr[0]); - - return result_seq2; -} - -ccv_bbf_classifier_cascade_t *ccv_bbf_read_classifier_cascade(const char *directory) -{ - char buf[1024]; - sprintf(buf, "%s/cascade.txt", directory); - int s, i; - FILE *r = fopen(buf, "r"); - if (r == 0) - return 0; - ccv_bbf_classifier_cascade_t *cascade = (ccv_bbf_classifier_cascade_t *)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); - s = fscanf(r, "%d %d %d", &cascade->count, &cascade->size.width, &cascade->size.height); - assert(s > 0); - cascade->stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(cascade->count * sizeof(ccv_bbf_stage_classifier_t)); - for (i = 0; i < cascade->count; i++) - { - sprintf(buf, "%s/stage-%d.txt", directory, i); - if (_ccv_read_bbf_stage_classifier(buf, &cascade->stage_classifier[i]) < 0) - { - cascade->count = i; - break; - } - } - fclose(r); - return cascade; -} - -ccv_bbf_classifier_cascade_t *ccv_bbf_classifier_cascade_read_binary(char *s) -{ - int i; - ccv_bbf_classifier_cascade_t *cascade = (ccv_bbf_classifier_cascade_t *)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); - memcpy(&cascade->count, s, sizeof(cascade->count)); - s += sizeof(cascade->count); - memcpy(&cascade->size.width, s, sizeof(cascade->size.width)); - s += sizeof(cascade->size.width); - memcpy(&cascade->size.height, s, sizeof(cascade->size.height)); - s += sizeof(cascade->size.height); - ccv_bbf_stage_classifier_t *classifier = cascade->stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(cascade->count * sizeof(ccv_bbf_stage_classifier_t)); - for (i = 0; i < cascade->count; i++, classifier++) - { - memcpy(&classifier->count, s, sizeof(classifier->count)); - s += sizeof(classifier->count); - memcpy(&classifier->threshold, s, sizeof(classifier->threshold)); - s += sizeof(classifier->threshold); - classifier->feature = (ccv_bbf_feature_t *)ccmalloc(classifier->count * sizeof(ccv_bbf_feature_t)); - classifier->alpha = (float *)ccmalloc(classifier->count * 2 * sizeof(float)); - memcpy(classifier->feature, s, classifier->count * sizeof(ccv_bbf_feature_t)); - s += classifier->count * sizeof(ccv_bbf_feature_t); - memcpy(classifier->alpha, s, classifier->count * 2 * sizeof(float)); - s += classifier->count * 2 * sizeof(float); - } - return cascade; -} - -int ccv_bbf_classifier_cascade_write_binary(ccv_bbf_classifier_cascade_t *cascade, char *s, int slen) -{ - int i; - int len = sizeof(cascade->count) + sizeof(cascade->size.width) + sizeof(cascade->size.height); - ccv_bbf_stage_classifier_t *classifier = cascade->stage_classifier; - for (i = 0; i < cascade->count; i++, classifier++) - len += sizeof(classifier->count) + sizeof(classifier->threshold) + classifier->count * sizeof(ccv_bbf_feature_t) + classifier->count * 2 * sizeof(float); - if (slen >= len) - { - memcpy(s, &cascade->count, sizeof(cascade->count)); - s += sizeof(cascade->count); - memcpy(s, &cascade->size.width, sizeof(cascade->size.width)); - s += sizeof(cascade->size.width); - memcpy(s, &cascade->size.height, sizeof(cascade->size.height)); - s += sizeof(cascade->size.height); - classifier = cascade->stage_classifier; - for (i = 0; i < cascade->count; i++, classifier++) - { - memcpy(s, &classifier->count, sizeof(classifier->count)); - s += sizeof(classifier->count); - memcpy(s, &classifier->threshold, sizeof(classifier->threshold)); - s += sizeof(classifier->threshold); - memcpy(s, classifier->feature, classifier->count * sizeof(ccv_bbf_feature_t)); - s += classifier->count * sizeof(ccv_bbf_feature_t); - memcpy(s, classifier->alpha, classifier->count * 2 * sizeof(float)); - s += classifier->count * 2 * sizeof(float); - } - } - return len; -} - -void ccv_bbf_classifier_cascade_free(ccv_bbf_classifier_cascade_t *cascade) -{ - int i; - for (i = 0; i < cascade->count; ++i) - { - ccfree(cascade->stage_classifier[i].feature); - ccfree(cascade->stage_classifier[i].alpha); - } - ccfree(cascade->stage_classifier); - ccfree(cascade); -} \ No newline at end of file diff --git a/test/source.c++ b/test/source.c++ index 6a6b390..97e29e8 100644 --- a/test/source.c++ +++ b/test/source.c++ @@ -88,1415 +88,4 @@ static int _ccv_read_bbf_stage_classifier(const char* file, ccv_bbf_stage_classi return 0; } -#ifdef HAVE_GSL - -static unsigned int _ccv_bbf_time_measure() -{ - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec * 1000000 + tv.tv_usec; -} - -#define less_than(a, b, aux) ((a) < (b)) -CCV_IMPLEMENT_QSORT(_ccv_sort_32f, float, less_than) -#undef less_than - -static void _ccv_bbf_eval_data(ccv_bbf_stage_classifier_t* classifier, unsigned char** posdata, int posnum, unsigned char** negdata, int negnum, ccv_size_t size, float* peval, float* neval) -{ - int i, j; - int steps[] = { _ccv_width_padding(size.width), - _ccv_width_padding(size.width >> 1), - _ccv_width_padding(size.width >> 2) }; - int isizs0 = steps[0] * size.height; - int isizs01 = isizs0 + steps[1] * (size.height >> 1); - for (i = 0; i < posnum; i++) - { - unsigned char* u8[] = { posdata[i], posdata[i] + isizs0, posdata[i] + isizs01 }; - float sum = 0; - float* alpha = classifier->alpha; - ccv_bbf_feature_t* feature = classifier->feature; - for (j = 0; j < classifier->count; ++j, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - peval[i] = sum; - } - for (i = 0; i < negnum; i++) - { - unsigned char* u8[] = { negdata[i], negdata[i] + isizs0, negdata[i] + isizs01 }; - float sum = 0; - float* alpha = classifier->alpha; - ccv_bbf_feature_t* feature = classifier->feature; - for (j = 0; j < classifier->count; ++j, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - neval[i] = sum; - } -} - -static int _ccv_prune_positive_data(ccv_bbf_classifier_cascade_t* cascade, unsigned char** posdata, int posnum, ccv_size_t size) -{ - float* peval = (float*)ccmalloc(posnum * sizeof(float)); - int i, j, k, rpos = posnum; - for (i = 0; i < cascade->count; i++) - { - _ccv_bbf_eval_data(cascade->stage_classifier + i, posdata, rpos, 0, 0, size, peval, 0); - k = 0; - for (j = 0; j < rpos; j++) - if (peval[j] >= cascade->stage_classifier[i].threshold) - { - posdata[k] = posdata[j]; - ++k; - } else { - ccfree(posdata[j]); - } - rpos = k; - } - ccfree(peval); - return rpos; -} - -static int _ccv_prepare_background_data(ccv_bbf_classifier_cascade_t* cascade, char** bgfiles, int bgnum, unsigned char** negdata, int negnum) -{ - int t, i, j, k, q; - int negperbg; - int negtotal = 0; - int steps[] = { _ccv_width_padding(cascade->size.width), - _ccv_width_padding(cascade->size.width >> 1), - _ccv_width_padding(cascade->size.width >> 2) }; - int isizs0 = steps[0] * cascade->size.height; - int isizs1 = steps[1] * (cascade->size.height >> 1); - int isizs2 = steps[2] * (cascade->size.height >> 2); - int* idcheck = (int*)ccmalloc(negnum * sizeof(int)); - - gsl_rng_env_setup(); - - gsl_rng* rng = gsl_rng_alloc(gsl_rng_default); - gsl_rng_set(rng, (unsigned long int)idcheck); - - ccv_size_t imgsz = cascade->size; - int rneg = negtotal; - for (t = 0; negtotal < negnum; t++) - { - PRINT(CCV_CLI_INFO, "preparing negative data ... 0%%"); - for (i = 0; i < bgnum; i++) - { - negperbg = (t < 2) ? (negnum - negtotal) / (bgnum - i) + 1 : negnum - negtotal; - ccv_dense_matrix_t* image = 0; - ccv_read(bgfiles[i], &image, CCV_IO_GRAY | CCV_IO_ANY_FILE); - assert((image->type & CCV_C1) && (image->type & CCV_8U)); - if (image == 0) - { - PRINT(CCV_CLI_ERROR, "\n%s file corrupted\n", bgfiles[i]); - continue; - } - if (t % 2 != 0) - ccv_flip(image, 0, 0, CCV_FLIP_X); - if (t % 4 >= 2) - ccv_flip(image, 0, 0, CCV_FLIP_Y); - ccv_bbf_param_t params = { .interval = 3, .min_neighbors = 0, .accurate = 1, .flags = 0, .size = cascade->size }; - ccv_array_t* detected = ccv_bbf_detect_objects(image, &cascade, 1, params); - memset(idcheck, 0, ccv_min(detected->rnum, negperbg) * sizeof(int)); - for (j = 0; j < ccv_min(detected->rnum, negperbg); j++) - { - int r = gsl_rng_uniform_int(rng, detected->rnum); - int flag = 1; - ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(detected, r); - while (flag) { - flag = 0; - for (k = 0; k < j; k++) - if (r == idcheck[k]) - { - flag = 1; - r = gsl_rng_uniform_int(rng, detected->rnum); - break; - } - rect = (ccv_rect_t*)ccv_array_get(detected, r); - if ((rect->x < 0) || (rect->y < 0) || (rect->width + rect->x > image->cols) || (rect->height + rect->y > image->rows)) - { - flag = 1; - r = gsl_rng_uniform_int(rng, detected->rnum); - } - } - idcheck[j] = r; - ccv_dense_matrix_t* temp = 0; - ccv_dense_matrix_t* imgs0 = 0; - ccv_dense_matrix_t* imgs1 = 0; - ccv_dense_matrix_t* imgs2 = 0; - ccv_slice(image, (ccv_matrix_t**)&temp, 0, rect->y, rect->x, rect->height, rect->width); - ccv_resample(temp, &imgs0, 0, imgsz.height, imgsz.width, CCV_INTER_AREA); - assert(imgs0->step == steps[0]); - ccv_matrix_free(temp); - ccv_sample_down(imgs0, &imgs1, 0, 0, 0); - assert(imgs1->step == steps[1]); - ccv_sample_down(imgs1, &imgs2, 0, 0, 0); - assert(imgs2->step == steps[2]); - - negdata[negtotal] = (unsigned char*)ccmalloc(isizs0 + isizs1 + isizs2); - unsigned char* u8s0 = negdata[negtotal]; - unsigned char* u8s1 = negdata[negtotal] + isizs0; - unsigned char* u8s2 = negdata[negtotal] + isizs0 + isizs1; - unsigned char* u8[] = { u8s0, u8s1, u8s2 }; - memcpy(u8s0, imgs0->data.u8, imgs0->rows * imgs0->step); - ccv_matrix_free(imgs0); - memcpy(u8s1, imgs1->data.u8, imgs1->rows * imgs1->step); - ccv_matrix_free(imgs1); - memcpy(u8s2, imgs2->data.u8, imgs2->rows * imgs2->step); - ccv_matrix_free(imgs2); - - flag = 1; - ccv_bbf_stage_classifier_t* classifier = cascade->stage_classifier; - for (k = 0; k < cascade->count; ++k, ++classifier) - { - float sum = 0; - float* alpha = classifier->alpha; - ccv_bbf_feature_t* feature = classifier->feature; - for (q = 0; q < classifier->count; ++q, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - if (sum < classifier->threshold) - { - flag = 0; - break; - } - } - if (!flag) - ccfree(negdata[negtotal]); - else { - ++negtotal; - if (negtotal >= negnum) - break; - } - } - ccv_array_free(detected); - ccv_matrix_free(image); - ccv_drain_cache(); - PRINT(CCV_CLI_INFO, "\rpreparing negative data ... %2d%%", 100 * negtotal / negnum); - fflush(0); - if (negtotal >= negnum) - break; - } - if (rneg == negtotal) - break; - rneg = negtotal; - PRINT(CCV_CLI_INFO, "\nentering additional round %d\n", t + 1); - } - gsl_rng_free(rng); - ccfree(idcheck); - ccv_drain_cache(); - PRINT(CCV_CLI_INFO, "\n"); - return negtotal; -} - -static void _ccv_prepare_positive_data(ccv_dense_matrix_t** posimg, unsigned char** posdata, ccv_size_t size, int posnum) -{ - PRINT(CCV_CLI_INFO, "preparing positive data ... 0%%"); - int i; - for (i = 0; i < posnum; i++) - { - ccv_dense_matrix_t* imgs0 = posimg[i]; - ccv_dense_matrix_t* imgs1 = 0; - ccv_dense_matrix_t* imgs2 = 0; - assert((imgs0->type & CCV_C1) && (imgs0->type & CCV_8U) && imgs0->rows == size.height && imgs0->cols == size.width); - ccv_sample_down(imgs0, &imgs1, 0, 0, 0); - ccv_sample_down(imgs1, &imgs2, 0, 0, 0); - int isizs0 = imgs0->rows * imgs0->step; - int isizs1 = imgs1->rows * imgs1->step; - int isizs2 = imgs2->rows * imgs2->step; - - posdata[i] = (unsigned char*)ccmalloc(isizs0 + isizs1 + isizs2); - memcpy(posdata[i], imgs0->data.u8, isizs0); - memcpy(posdata[i] + isizs0, imgs1->data.u8, isizs1); - memcpy(posdata[i] + isizs0 + isizs1, imgs2->data.u8, isizs2); - - PRINT(CCV_CLI_INFO, "\rpreparing positive data ... %2d%%", 100 * (i + 1) / posnum); - fflush(0); - - ccv_matrix_free(imgs1); - ccv_matrix_free(imgs2); - } - ccv_drain_cache(); - PRINT(CCV_CLI_INFO, "\n"); -} - -typedef struct { - double fitness; - int pk, nk; - int age; - double error; - ccv_bbf_feature_t feature; -} ccv_bbf_gene_t; - -static inline void _ccv_bbf_genetic_fitness(ccv_bbf_gene_t* gene) -{ - gene->fitness = (1 - gene->error) * exp(-0.01 * gene->age) * exp((gene->pk + gene->nk) * log(1.015)); -} - -static inline int _ccv_bbf_exist_gene_feature(ccv_bbf_gene_t* gene, int x, int y, int z) -{ - int i; - for (i = 0; i < gene->pk; i++) - if (z == gene->feature.pz[i] && x == gene->feature.px[i] && y == gene->feature.py[i]) - return 1; - for (i = 0; i < gene->nk; i++) - if (z == gene->feature.nz[i] && x == gene->feature.nx[i] && y == gene->feature.ny[i]) - return 1; - return 0; -} - -static inline void _ccv_bbf_randomize_gene(gsl_rng* rng, ccv_bbf_gene_t* gene, int* rows, int* cols) -{ - int i; - do { - gene->pk = gsl_rng_uniform_int(rng, CCV_BBF_POINT_MAX - 1) + 1; - gene->nk = gsl_rng_uniform_int(rng, CCV_BBF_POINT_MAX - 1) + 1; - } while (gene->pk + gene->nk < CCV_BBF_POINT_MIN); /* a hard restriction of at least 3 points have to be examed */ - gene->feature.size = ccv_max(gene->pk, gene->nk); - gene->age = 0; - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - { - gene->feature.pz[i] = -1; - gene->feature.nz[i] = -1; - } - int x, y, z; - for (i = 0; i < gene->pk; i++) - { - do { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(gene, x, y, z)); - gene->feature.pz[i] = z; - gene->feature.px[i] = x; - gene->feature.py[i] = y; - } - for (i = 0; i < gene->nk; i++) - { - do { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while ( _ccv_bbf_exist_gene_feature(gene, x, y, z)); - gene->feature.nz[i] = z; - gene->feature.nx[i] = x; - gene->feature.ny[i] = y; - } -} - -static inline double _ccv_bbf_error_rate(ccv_bbf_feature_t* feature, unsigned char** posdata, int posnum, unsigned char** negdata, int negnum, ccv_size_t size, double* pw, double* nw) -{ - int i; - int steps[] = { _ccv_width_padding(size.width), - _ccv_width_padding(size.width >> 1), - _ccv_width_padding(size.width >> 2) }; - int isizs0 = steps[0] * size.height; - int isizs01 = isizs0 + steps[1] * (size.height >> 1); - double error = 0; - for (i = 0; i < posnum; i++) - { - unsigned char* u8[] = { posdata[i], posdata[i] + isizs0, posdata[i] + isizs01 }; - if (!_ccv_run_bbf_feature(feature, steps, u8)) - error += pw[i]; - } - for (i = 0; i < negnum; i++) - { - unsigned char* u8[] = { negdata[i], negdata[i] + isizs0, negdata[i] + isizs01 }; - if ( _ccv_run_bbf_feature(feature, steps, u8)) - error += nw[i]; - } - return error; -} - -#define less_than(fit1, fit2, aux) ((fit1).fitness >= (fit2).fitness) -static CCV_IMPLEMENT_QSORT(_ccv_bbf_genetic_qsort, ccv_bbf_gene_t, less_than) -#undef less_than - -static ccv_bbf_feature_t _ccv_bbf_genetic_optimize(unsigned char** posdata, int posnum, unsigned char** negdata, int negnum, int ftnum, ccv_size_t size, double* pw, double* nw) -{ - ccv_bbf_feature_t best; - /* seed (random method) */ - gsl_rng_env_setup(); - gsl_rng* rng = gsl_rng_alloc(gsl_rng_default); - union { unsigned long int li; double db; } dbli; - dbli.db = pw[0] + nw[0]; - gsl_rng_set(rng, dbli.li); - int i, j; - int pnum = ftnum * 100; - assert(pnum > 0); - ccv_bbf_gene_t* gene = (ccv_bbf_gene_t*)ccmalloc(pnum * sizeof(ccv_bbf_gene_t)); - int rows[] = { size.height, size.height >> 1, size.height >> 2 }; - int cols[] = { size.width, size.width >> 1, size.width >> 2 }; - for (i = 0; i < pnum; i++) - _ccv_bbf_randomize_gene(rng, &gene[i], rows, cols); - unsigned int timer = _ccv_bbf_time_measure(); -#ifdef USE_OPENMP -#pragma omp parallel for private(i) schedule(dynamic) -#endif - for (i = 0; i < pnum; i++) - gene[i].error = _ccv_bbf_error_rate(&gene[i].feature, posdata, posnum, negdata, negnum, size, pw, nw); - timer = _ccv_bbf_time_measure() - timer; - for (i = 0; i < pnum; i++) - _ccv_bbf_genetic_fitness(&gene[i]); - double best_err = 1; - int rnum = ftnum * 39; /* number of randomize */ - int mnum = ftnum * 40; /* number of mutation */ - int hnum = ftnum * 20; /* number of hybrid */ - /* iteration stop crit : best no change in 40 iterations */ - int it = 0, t; - for (t = 0 ; it < 40; ++it, ++t) - { - int min_id = 0; - double min_err = gene[0].error; - for (i = 1; i < pnum; i++) - if (gene[i].error < min_err) - { - min_id = i; - min_err = gene[i].error; - } - min_err = gene[min_id].error = _ccv_bbf_error_rate(&gene[min_id].feature, posdata, posnum, negdata, negnum, size, pw, nw); - if (min_err < best_err) - { - best_err = min_err; - memcpy(&best, &gene[min_id].feature, sizeof(best)); - PRINT(CCV_CLI_INFO, "best bbf feature with error %f\n|-size: %d\n|-positive point: ", best_err, best.size); - for (i = 0; i < best.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", best.px[i], best.py[i], best.pz[i]); - PRINT(CCV_CLI_INFO, "\n|-negative point: "); - for (i = 0; i < best.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", best.nx[i], best.ny[i], best.nz[i]); - PRINT(CCV_CLI_INFO, "\n"); - it = 0; - } - PRINT(CCV_CLI_INFO, "minimum error achieved in round %d(%d) : %f with %d ms\n", t, it, min_err, timer / 1000); - _ccv_bbf_genetic_qsort(gene, pnum, 0); - for (i = 0; i < ftnum; i++) - ++gene[i].age; - for (i = ftnum; i < ftnum + mnum; i++) - { - int parent = gsl_rng_uniform_int(rng, ftnum); - memcpy(gene + i, gene + parent, sizeof(ccv_bbf_gene_t)); - /* three mutation strategy : 1. add, 2. remove, 3. refine */ - int pnm, pn = gsl_rng_uniform_int(rng, 2); - int* pnk[] = { &gene[i].pk, &gene[i].nk }; - int* pnx[] = { gene[i].feature.px, gene[i].feature.nx }; - int* pny[] = { gene[i].feature.py, gene[i].feature.ny }; - int* pnz[] = { gene[i].feature.pz, gene[i].feature.nz }; - int x, y, z; - int victim, decay = 1; - do { - switch (gsl_rng_uniform_int(rng, 3)) - { - case 0: /* add */ - if (gene[i].pk == CCV_BBF_POINT_MAX && gene[i].nk == CCV_BBF_POINT_MAX) - break; - while (*pnk[pn] + 1 > CCV_BBF_POINT_MAX) - pn = gsl_rng_uniform_int(rng, 2); - do { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(&gene[i], x, y, z)); - pnz[pn][*pnk[pn]] = z; - pnx[pn][*pnk[pn]] = x; - pny[pn][*pnk[pn]] = y; - ++(*pnk[pn]); - gene[i].feature.size = ccv_max(gene[i].pk, gene[i].nk); - decay = gene[i].age = 0; - break; - case 1: /* remove */ - if (gene[i].pk + gene[i].nk <= CCV_BBF_POINT_MIN) /* at least 3 points have to be examed */ - break; - while (*pnk[pn] - 1 <= 0) // || *pnk[pn] + *pnk[!pn] - 1 < CCV_BBF_POINT_MIN) - pn = gsl_rng_uniform_int(rng, 2); - victim = gsl_rng_uniform_int(rng, *pnk[pn]); - for (j = victim; j < *pnk[pn] - 1; j++) - { - pnz[pn][j] = pnz[pn][j + 1]; - pnx[pn][j] = pnx[pn][j + 1]; - pny[pn][j] = pny[pn][j + 1]; - } - pnz[pn][*pnk[pn] - 1] = -1; - --(*pnk[pn]); - gene[i].feature.size = ccv_max(gene[i].pk, gene[i].nk); - decay = gene[i].age = 0; - break; - case 2: /* refine */ - pnm = gsl_rng_uniform_int(rng, *pnk[pn]); - do { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(&gene[i], x, y, z)); - pnz[pn][pnm] = z; - pnx[pn][pnm] = x; - pny[pn][pnm] = y; - decay = gene[i].age = 0; - break; - } - } while (decay); - } - for (i = ftnum + mnum; i < ftnum + mnum + hnum; i++) - { - /* hybrid strategy: taking positive points from dad, negative points from mum */ - int dad, mum; - do { - dad = gsl_rng_uniform_int(rng, ftnum); - mum = gsl_rng_uniform_int(rng, ftnum); - } while (dad == mum || gene[dad].pk + gene[mum].nk < CCV_BBF_POINT_MIN); /* at least 3 points have to be examed */ - for (j = 0; j < CCV_BBF_POINT_MAX; j++) - { - gene[i].feature.pz[j] = -1; - gene[i].feature.nz[j] = -1; - } - gene[i].pk = gene[dad].pk; - for (j = 0; j < gene[i].pk; j++) - { - gene[i].feature.pz[j] = gene[dad].feature.pz[j]; - gene[i].feature.px[j] = gene[dad].feature.px[j]; - gene[i].feature.py[j] = gene[dad].feature.py[j]; - } - gene[i].nk = gene[mum].nk; - for (j = 0; j < gene[i].nk; j++) - { - gene[i].feature.nz[j] = gene[mum].feature.nz[j]; - gene[i].feature.nx[j] = gene[mum].feature.nx[j]; - gene[i].feature.ny[j] = gene[mum].feature.ny[j]; - } - gene[i].feature.size = ccv_max(gene[i].pk, gene[i].nk); - gene[i].age = 0; - } - for (i = ftnum + mnum + hnum; i < ftnum + mnum + hnum + rnum; i++) - _ccv_bbf_randomize_gene(rng, &gene[i], rows, cols); - timer = _ccv_bbf_time_measure(); -#ifdef USE_OPENMP -#pragma omp parallel for private(i) schedule(dynamic) -#endif - for (i = 0; i < pnum; i++) - gene[i].error = _ccv_bbf_error_rate(&gene[i].feature, posdata, posnum, negdata, negnum, size, pw, nw); - timer = _ccv_bbf_time_measure() - timer; - for (i = 0; i < pnum; i++) - _ccv_bbf_genetic_fitness(&gene[i]); - } - ccfree(gene); - gsl_rng_free(rng); - return best; -} - -#define less_than(fit1, fit2, aux) ((fit1).error < (fit2).error) -static CCV_IMPLEMENT_QSORT(_ccv_bbf_best_qsort, ccv_bbf_gene_t, less_than) -#undef less_than - -static ccv_bbf_gene_t _ccv_bbf_best_gene(ccv_bbf_gene_t* gene, int pnum, int point_min, unsigned char** posdata, int posnum, unsigned char** negdata, int negnum, ccv_size_t size, double* pw, double* nw) -{ - int i; - unsigned int timer = _ccv_bbf_time_measure(); -#ifdef USE_OPENMP -#pragma omp parallel for private(i) schedule(dynamic) -#endif - for (i = 0; i < pnum; i++) - gene[i].error = _ccv_bbf_error_rate(&gene[i].feature, posdata, posnum, negdata, negnum, size, pw, nw); - timer = _ccv_bbf_time_measure() - timer; - _ccv_bbf_best_qsort(gene, pnum, 0); - int min_id = 0; - double min_err = gene[0].error; - for (i = 0; i < pnum; i++) - if (gene[i].nk + gene[i].pk >= point_min) - { - min_id = i; - min_err = gene[i].error; - break; - } - PRINT(CCV_CLI_INFO, "local best bbf feature with error %f\n|-size: %d\n|-positive point: ", min_err, gene[min_id].feature.size); - for (i = 0; i < gene[min_id].feature.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", gene[min_id].feature.px[i], gene[min_id].feature.py[i], gene[min_id].feature.pz[i]); - PRINT(CCV_CLI_INFO, "\n|-negative point: "); - for (i = 0; i < gene[min_id].feature.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", gene[min_id].feature.nx[i], gene[min_id].feature.ny[i], gene[min_id].feature.nz[i]); - PRINT(CCV_CLI_INFO, "\nthe computation takes %d ms\n", timer / 1000); - return gene[min_id]; -} - -static ccv_bbf_feature_t _ccv_bbf_convex_optimize(unsigned char** posdata, int posnum, unsigned char** negdata, int negnum, ccv_bbf_feature_t* best_feature, ccv_size_t size, double* pw, double* nw) -{ - ccv_bbf_gene_t best_gene; - /* seed (random method) */ - gsl_rng_env_setup(); - gsl_rng* rng = gsl_rng_alloc(gsl_rng_default); - union { unsigned long int li; double db; } dbli; - dbli.db = pw[0] + nw[0]; - gsl_rng_set(rng, dbli.li); - int i, j, k, q, p, g, t; - int rows[] = { size.height, size.height >> 1, size.height >> 2 }; - int cols[] = { size.width, size.width >> 1, size.width >> 2 }; - int pnum = rows[0] * cols[0] + rows[1] * cols[1] + rows[2] * cols[2]; - ccv_bbf_gene_t* gene = (ccv_bbf_gene_t*)ccmalloc((pnum * (CCV_BBF_POINT_MAX * 2 + 1) * 2 + CCV_BBF_POINT_MAX * 2 + 1) * sizeof(ccv_bbf_gene_t)); - if (best_feature == 0) - { - /* bootstrapping the best feature, start from two pixels, one for positive, one for negative - * the bootstrapping process go like this: first, it will assign a random pixel as positive - * and enumerate every possible pixel as negative, and pick the best one. Then, enumerate every - * possible pixel as positive, and pick the best one, until it converges */ - memset(&best_gene, 0, sizeof(ccv_bbf_gene_t)); - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - best_gene.feature.pz[i] = best_gene.feature.nz[i] = -1; - best_gene.pk = 1; - best_gene.nk = 0; - best_gene.feature.size = 1; - best_gene.feature.pz[0] = gsl_rng_uniform_int(rng, 3); - best_gene.feature.px[0] = gsl_rng_uniform_int(rng, cols[best_gene.feature.pz[0]]); - best_gene.feature.py[0] = gsl_rng_uniform_int(rng, rows[best_gene.feature.pz[0]]); - for (t = 0; ; ++t) - { - g = 0; - if (t % 2 == 0) - { - for (i = 0; i < 3; i++) - for (j = 0; j < cols[i]; j++) - for (k = 0; k < rows[i]; k++) - if (i != best_gene.feature.pz[0] || j != best_gene.feature.px[0] || k != best_gene.feature.py[0]) - { - gene[g] = best_gene; - gene[g].pk = gene[g].nk = 1; - gene[g].feature.nz[0] = i; - gene[g].feature.nx[0] = j; - gene[g].feature.ny[0] = k; - g++; - } - } else { - for (i = 0; i < 3; i++) - for (j = 0; j < cols[i]; j++) - for (k = 0; k < rows[i]; k++) - if (i != best_gene.feature.nz[0] || j != best_gene.feature.nx[0] || k != best_gene.feature.ny[0]) - { - gene[g] = best_gene; - gene[g].pk = gene[g].nk = 1; - gene[g].feature.pz[0] = i; - gene[g].feature.px[0] = j; - gene[g].feature.py[0] = k; - g++; - } - } - PRINT(CCV_CLI_INFO, "bootstrapping round : %d\n", t); - ccv_bbf_gene_t local_gene = _ccv_bbf_best_gene(gene, g, 2, posdata, posnum, negdata, negnum, size, pw, nw); - if (local_gene.error >= best_gene.error - 1e-10) - break; - best_gene = local_gene; - } - } else { - best_gene.feature = *best_feature; - best_gene.pk = best_gene.nk = best_gene.feature.size; - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - if (best_feature->pz[i] == -1) - { - best_gene.pk = i; - break; - } - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - if (best_feature->nz[i] == -1) - { - best_gene.nk = i; - break; - } - } - /* after bootstrapping, the float search technique will do the following permutations: - * a). add a new point to positive or negative - * b). remove a point from positive or negative - * c). move an existing point in positive or negative to another position - * the three rules applied exhaustively, no heuristic used. */ - for (t = 0; ; ++t) - { - g = 0; - for (i = 0; i < 3; i++) - for (j = 0; j < cols[i]; j++) - for (k = 0; k < rows[i]; k++) - if (!_ccv_bbf_exist_gene_feature(&best_gene, j, k, i)) - { - /* add positive point */ - if (best_gene.pk < CCV_BBF_POINT_MAX - 1) - { - gene[g] = best_gene; - gene[g].feature.pz[gene[g].pk] = i; - gene[g].feature.px[gene[g].pk] = j; - gene[g].feature.py[gene[g].pk] = k; - gene[g].pk++; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - /* add negative point */ - if (best_gene.nk < CCV_BBF_POINT_MAX - 1) - { - gene[g] = best_gene; - gene[g].feature.nz[gene[g].nk] = i; - gene[g].feature.nx[gene[g].nk] = j; - gene[g].feature.ny[gene[g].nk] = k; - gene[g].nk++; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - /* refine positive point */ - for (q = 0; q < best_gene.pk; q++) - { - gene[g] = best_gene; - gene[g].feature.pz[q] = i; - gene[g].feature.px[q] = j; - gene[g].feature.py[q] = k; - g++; - } - /* add positive point, remove negative point */ - if (best_gene.pk < CCV_BBF_POINT_MAX - 1 && best_gene.nk > 1) - { - for (q = 0; q < best_gene.nk; q++) - { - gene[g] = best_gene; - gene[g].feature.pz[gene[g].pk] = i; - gene[g].feature.px[gene[g].pk] = j; - gene[g].feature.py[gene[g].pk] = k; - gene[g].pk++; - for (p = q; p < best_gene.nk - 1; p++) - { - gene[g].feature.nz[p] = gene[g].feature.nz[p + 1]; - gene[g].feature.nx[p] = gene[g].feature.nx[p + 1]; - gene[g].feature.ny[p] = gene[g].feature.ny[p + 1]; - } - gene[g].feature.nz[gene[g].nk - 1] = -1; - gene[g].nk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - } - /* refine negative point */ - for (q = 0; q < best_gene.nk; q++) - { - gene[g] = best_gene; - gene[g].feature.nz[q] = i; - gene[g].feature.nx[q] = j; - gene[g].feature.ny[q] = k; - g++; - } - /* add negative point, remove positive point */ - if (best_gene.pk > 1 && best_gene.nk < CCV_BBF_POINT_MAX - 1) - { - for (q = 0; q < best_gene.pk; q++) - { - gene[g] = best_gene; - gene[g].feature.nz[gene[g].nk] = i; - gene[g].feature.nx[gene[g].nk] = j; - gene[g].feature.ny[gene[g].nk] = k; - gene[g].nk++; - for (p = q; p < best_gene.pk - 1; p++) - { - gene[g].feature.pz[p] = gene[g].feature.pz[p + 1]; - gene[g].feature.px[p] = gene[g].feature.px[p + 1]; - gene[g].feature.py[p] = gene[g].feature.py[p + 1]; - } - gene[g].feature.pz[gene[g].pk - 1] = -1; - gene[g].pk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - } - } - if (best_gene.pk > 1) - for (q = 0; q < best_gene.pk; q++) - { - gene[g] = best_gene; - for (i = q; i < best_gene.pk - 1; i++) - { - gene[g].feature.pz[i] = gene[g].feature.pz[i + 1]; - gene[g].feature.px[i] = gene[g].feature.px[i + 1]; - gene[g].feature.py[i] = gene[g].feature.py[i + 1]; - } - gene[g].feature.pz[gene[g].pk - 1] = -1; - gene[g].pk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - if (best_gene.nk > 1) - for (q = 0; q < best_gene.nk; q++) - { - gene[g] = best_gene; - for (i = q; i < best_gene.nk - 1; i++) - { - gene[g].feature.nz[i] = gene[g].feature.nz[i + 1]; - gene[g].feature.nx[i] = gene[g].feature.nx[i + 1]; - gene[g].feature.ny[i] = gene[g].feature.ny[i + 1]; - } - gene[g].feature.nz[gene[g].nk - 1] = -1; - gene[g].nk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - gene[g] = best_gene; - g++; - PRINT(CCV_CLI_INFO, "float search round : %d\n", t); - ccv_bbf_gene_t local_gene = _ccv_bbf_best_gene(gene, g, CCV_BBF_POINT_MIN, posdata, posnum, negdata, negnum, size, pw, nw); - if (local_gene.error >= best_gene.error - 1e-10) - break; - best_gene = local_gene; - } - ccfree(gene); - gsl_rng_free(rng); - return best_gene.feature; -} - -static int _ccv_write_bbf_stage_classifier(const char* file, ccv_bbf_stage_classifier_t* classifier) -{ - FILE* w = fopen(file, "wb"); - if (w == 0) return -1; - fprintf(w, "%d\n", classifier->count); - union { float fl; int i; } fli; - fli.fl = classifier->threshold; - fprintf(w, "%d\n", fli.i); - int i, j; - for (i = 0; i < classifier->count; i++) - { - fprintf(w, "%d\n", classifier->feature[i].size); - for (j = 0; j < classifier->feature[i].size; j++) - { - fprintf(w, "%d %d %d\n", classifier->feature[i].px[j], classifier->feature[i].py[j], classifier->feature[i].pz[j]); - fprintf(w, "%d %d %d\n", classifier->feature[i].nx[j], classifier->feature[i].ny[j], classifier->feature[i].nz[j]); - } - union { float fl; int i; } flia, flib; - flia.fl = classifier->alpha[i * 2]; - flib.fl = classifier->alpha[i * 2 + 1]; - fprintf(w, "%d %d\n", flia.i, flib.i); - } - fclose(w); - return 0; -} - -static int _ccv_read_background_data(const char* file, unsigned char** negdata, int* negnum, ccv_size_t size) -{ - int stat = 0; - FILE* r = fopen(file, "rb"); - if (r == 0) return -1; - stat |= fread(negnum, sizeof(int), 1, r); - int i; - int isizs012 = _ccv_width_padding(size.width) * size.height + - _ccv_width_padding(size.width >> 1) * (size.height >> 1) + - _ccv_width_padding(size.width >> 2) * (size.height >> 2); - for (i = 0; i < *negnum; i++) - { - negdata[i] = (unsigned char*)ccmalloc(isizs012); - stat |= fread(negdata[i], 1, isizs012, r); - } - fclose(r); - return 0; -} - -static int _ccv_write_background_data(const char* file, unsigned char** negdata, int negnum, ccv_size_t size) -{ - FILE* w = fopen(file, "w"); - if (w == 0) return -1; - fwrite(&negnum, sizeof(int), 1, w); - int i; - int isizs012 = _ccv_width_padding(size.width) * size.height + - _ccv_width_padding(size.width >> 1) * (size.height >> 1) + - _ccv_width_padding(size.width >> 2) * (size.height >> 2); - for (i = 0; i < negnum; i++) - fwrite(negdata[i], 1, isizs012, w); - fclose(w); - return 0; -} - -static int _ccv_resume_bbf_cascade_training_state(const char* file, int* i, int* k, int* bg, double* pw, double* nw, int posnum, int negnum) -{ - int stat = 0; - FILE* r = fopen(file, "r"); - if (r == 0) return -1; - stat |= fscanf(r, "%d %d %d", i, k, bg); - int j; - union { double db; int i[2]; } dbi; - for (j = 0; j < posnum; j++) - { - stat |= fscanf(r, "%d %d", &dbi.i[0], &dbi.i[1]); - pw[j] = dbi.db; - } - for (j = 0; j < negnum; j++) - { - stat |= fscanf(r, "%d %d", &dbi.i[0], &dbi.i[1]); - nw[j] = dbi.db; - } - fclose(r); - return 0; -} - -static int _ccv_save_bbf_cacade_training_state(const char* file, int i, int k, int bg, double* pw, double* nw, int posnum, int negnum) -{ - FILE* w = fopen(file, "w"); - if (w == 0) return -1; - fprintf(w, "%d %d %d\n", i, k, bg); - int j; - union { double db; int i[2]; } dbi; - for (j = 0; j < posnum; ++j) - { - dbi.db = pw[j]; - fprintf(w, "%d %d ", dbi.i[0], dbi.i[1]); - } - fprintf(w, "\n"); - for (j = 0; j < negnum; ++j) - { - dbi.db = nw[j]; - fprintf(w, "%d %d ", dbi.i[0], dbi.i[1]); - } - fprintf(w, "\n"); - fclose(w); - return 0; -} - -void ccv_bbf_classifier_cascade_new(ccv_dense_matrix_t** posimg, int posnum, char** bgfiles, int bgnum, int negnum, ccv_size_t size, const char* dir, ccv_bbf_new_param_t params) -{ - int i, j, k; - /* allocate memory for usage */ - ccv_bbf_classifier_cascade_t* cascade = (ccv_bbf_classifier_cascade_t*)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); - cascade->count = 0; - cascade->size = size; - cascade->stage_classifier = (ccv_bbf_stage_classifier_t*)ccmalloc(sizeof(ccv_bbf_stage_classifier_t)); - unsigned char** posdata = (unsigned char**)ccmalloc(posnum * sizeof(unsigned char*)); - unsigned char** negdata = (unsigned char**)ccmalloc(negnum * sizeof(unsigned char*)); - double* pw = (double*)ccmalloc(posnum * sizeof(double)); - double* nw = (double*)ccmalloc(negnum * sizeof(double)); - float* peval = (float*)ccmalloc(posnum * sizeof(float)); - float* neval = (float*)ccmalloc(negnum * sizeof(float)); - double inv_balance_k = 1. / params.balance_k; - /* balance factor k, and weighted with 0.01 */ - params.balance_k *= 0.01; - inv_balance_k *= 0.01; - - int steps[] = { _ccv_width_padding(cascade->size.width), - _ccv_width_padding(cascade->size.width >> 1), - _ccv_width_padding(cascade->size.width >> 2) }; - int isizs0 = steps[0] * cascade->size.height; - int isizs01 = isizs0 + steps[1] * (cascade->size.height >> 1); - - i = 0; - k = 0; - int bg = 0; - int cacheK = 10; - /* state resume code */ - char buf[1024]; - sprintf(buf, "%s/stat.txt", dir); - _ccv_resume_bbf_cascade_training_state(buf, &i, &k, &bg, pw, nw, posnum, negnum); - if (i > 0) - { - cascade->count = i; - ccfree(cascade->stage_classifier); - cascade->stage_classifier = (ccv_bbf_stage_classifier_t*)ccmalloc(i * sizeof(ccv_bbf_stage_classifier_t)); - for (j = 0; j < i; j++) - { - sprintf(buf, "%s/stage-%d.txt", dir, j); - _ccv_read_bbf_stage_classifier(buf, &cascade->stage_classifier[j]); - } - } - if (k > 0) - cacheK = k; - int rpos, rneg = 0; - if (bg) - { - sprintf(buf, "%s/negs.txt", dir); - _ccv_read_background_data(buf, negdata, &rneg, cascade->size); - } - - for (; i < params.layer; i++) - { - if (!bg) - { - rneg = _ccv_prepare_background_data(cascade, bgfiles, bgnum, negdata, negnum); - /* save state of background data */ - sprintf(buf, "%s/negs.txt", dir); - _ccv_write_background_data(buf, negdata, rneg, cascade->size); - bg = 1; - } - double totalw; - /* save state of cascade : level, weight etc. */ - sprintf(buf, "%s/stat.txt", dir); - _ccv_save_bbf_cacade_training_state(buf, i, k, bg, pw, nw, posnum, negnum); - ccv_bbf_stage_classifier_t classifier; - if (k > 0) - { - /* resume state of classifier */ - sprintf( buf, "%s/stage-%d.txt", dir, i ); - _ccv_read_bbf_stage_classifier(buf, &classifier); - } else { - /* initialize classifier */ - for (j = 0; j < posnum; j++) - pw[j] = params.balance_k; - for (j = 0; j < rneg; j++) - nw[j] = inv_balance_k; - classifier.count = k; - classifier.threshold = 0; - classifier.feature = (ccv_bbf_feature_t*)ccmalloc(cacheK * sizeof(ccv_bbf_feature_t)); - classifier.alpha = (float*)ccmalloc(cacheK * 2 * sizeof(float)); - } - _ccv_prepare_positive_data(posimg, posdata, cascade->size, posnum); - rpos = _ccv_prune_positive_data(cascade, posdata, posnum, cascade->size); - PRINT(CCV_CLI_INFO, "%d postivie data and %d negative data in training\n", rpos, rneg); - /* reweight to 1.00 */ - totalw = 0; - for (j = 0; j < rpos; j++) - totalw += pw[j]; - for (j = 0; j < rneg; j++) - totalw += nw[j]; - for (j = 0; j < rpos; j++) - pw[j] = pw[j] / totalw; - for (j = 0; j < rneg; j++) - nw[j] = nw[j] / totalw; - for (; ; k++) - { - /* get overall true-positive, false-positive rate and threshold */ - double tp = 0, fp = 0, etp = 0, efp = 0; - _ccv_bbf_eval_data(&classifier, posdata, rpos, negdata, rneg, cascade->size, peval, neval); - _ccv_sort_32f(peval, rpos, 0); - classifier.threshold = peval[(int)((1. - params.pos_crit) * rpos)] - 1e-6; - for (j = 0; j < rpos; j++) - { - if (peval[j] >= 0) - ++tp; - if (peval[j] >= classifier.threshold) - ++etp; - } - tp /= rpos; etp /= rpos; - for (j = 0; j < rneg; j++) - { - if (neval[j] >= 0) - ++fp; - if (neval[j] >= classifier.threshold) - ++efp; - } - fp /= rneg; efp /= rneg; - PRINT(CCV_CLI_INFO, "stage classifier real TP rate : %f, FP rate : %f\n", tp, fp); - PRINT(CCV_CLI_INFO, "stage classifier TP rate : %f, FP rate : %f at threshold : %f\n", etp, efp, classifier.threshold); - if (k > 0) - { - /* save classifier state */ - sprintf(buf, "%s/stage-%d.txt", dir, i); - _ccv_write_bbf_stage_classifier(buf, &classifier); - sprintf(buf, "%s/stat.txt", dir); - _ccv_save_bbf_cacade_training_state(buf, i, k, bg, pw, nw, posnum, negnum); - } - if (etp > params.pos_crit && efp < params.neg_crit) - break; - /* TODO: more post-process is needed in here */ - - /* select the best feature in current distribution through genetic algorithm optimization */ - ccv_bbf_feature_t best; - if (params.optimizer == CCV_BBF_GENETIC_OPT) - { - best = _ccv_bbf_genetic_optimize(posdata, rpos, negdata, rneg, params.feature_number, cascade->size, pw, nw); - } else if (params.optimizer == CCV_BBF_FLOAT_OPT) { - best = _ccv_bbf_convex_optimize(posdata, rpos, negdata, rneg, 0, cascade->size, pw, nw); - } else { - best = _ccv_bbf_genetic_optimize(posdata, rpos, negdata, rneg, params.feature_number, cascade->size, pw, nw); - best = _ccv_bbf_convex_optimize(posdata, rpos, negdata, rneg, &best, cascade->size, pw, nw); - } - double err = _ccv_bbf_error_rate(&best, posdata, rpos, negdata, rneg, cascade->size, pw, nw); - double rw = (1 - err) / err; - totalw = 0; - /* reweight */ - for (j = 0; j < rpos; j++) - { - unsigned char* u8[] = { posdata[j], posdata[j] + isizs0, posdata[j] + isizs01 }; - if (!_ccv_run_bbf_feature(&best, steps, u8)) - pw[j] *= rw; - pw[j] *= params.balance_k; - totalw += pw[j]; - } - for (j = 0; j < rneg; j++) - { - unsigned char* u8[] = { negdata[j], negdata[j] + isizs0, negdata[j] + isizs01 }; - if (_ccv_run_bbf_feature(&best, steps, u8)) - nw[j] *= rw; - nw[j] *= inv_balance_k; - totalw += nw[j]; - } - for (j = 0; j < rpos; j++) - pw[j] = pw[j] / totalw; - for (j = 0; j < rneg; j++) - nw[j] = nw[j] / totalw; - double c = log(rw); - PRINT(CCV_CLI_INFO, "coefficient of feature %d: %f\n", k + 1, c); - classifier.count = k + 1; - /* resizing classifier */ - if (k >= cacheK) - { - ccv_bbf_feature_t* feature = (ccv_bbf_feature_t*)ccmalloc(cacheK * 2 * sizeof(ccv_bbf_feature_t)); - memcpy(feature, classifier.feature, cacheK * sizeof(ccv_bbf_feature_t)); - ccfree(classifier.feature); - float* alpha = (float*)ccmalloc(cacheK * 4 * sizeof(float)); - memcpy(alpha, classifier.alpha, cacheK * 2 * sizeof(float)); - ccfree(classifier.alpha); - classifier.feature = feature; - classifier.alpha = alpha; - cacheK *= 2; - } - /* setup new feature */ - classifier.feature[k] = best; - classifier.alpha[k * 2] = -c; - classifier.alpha[k * 2 + 1] = c; - } - cascade->count = i + 1; - ccv_bbf_stage_classifier_t* stage_classifier = (ccv_bbf_stage_classifier_t*)ccmalloc(cascade->count * sizeof(ccv_bbf_stage_classifier_t)); - memcpy(stage_classifier, cascade->stage_classifier, i * sizeof(ccv_bbf_stage_classifier_t)); - ccfree(cascade->stage_classifier); - stage_classifier[i] = classifier; - cascade->stage_classifier = stage_classifier; - k = 0; - bg = 0; - for (j = 0; j < rpos; j++) - ccfree(posdata[j]); - for (j = 0; j < rneg; j++) - ccfree(negdata[j]); - } - - ccfree(neval); - ccfree(peval); - ccfree(nw); - ccfree(pw); - ccfree(negdata); - ccfree(posdata); - ccfree(cascade); -} -#else -void ccv_bbf_classifier_cascade_new(ccv_dense_matrix_t** posimg, int posnum, char** bgfiles, int bgnum, int negnum, ccv_size_t size, const char* dir, ccv_bbf_new_param_t params) -{ - fprintf(stderr, " ccv_bbf_classifier_cascade_new requires libgsl support, please compile ccv with libgsl.\n"); -} -#endif - -static int _ccv_is_equal(const void* _r1, const void* _r2, void* data) -{ - const ccv_comp_t* r1 = (const ccv_comp_t*)_r1; - const ccv_comp_t* r2 = (const ccv_comp_t*)_r2; - int distance = (int)(r1->rect.width * 0.25 + 0.5); - - return r2->rect.x <= r1->rect.x + distance && - r2->rect.x >= r1->rect.x - distance && - r2->rect.y <= r1->rect.y + distance && - r2->rect.y >= r1->rect.y - distance && - r2->rect.width <= (int)(r1->rect.width * 1.5 + 0.5) && - (int)(r2->rect.width * 1.5 + 0.5) >= r1->rect.width; -} - -static int _ccv_is_equal_same_class(const void* _r1, const void* _r2, void* data) -{ - const ccv_comp_t* r1 = (const ccv_comp_t*)_r1; - const ccv_comp_t* r2 = (const ccv_comp_t*)_r2; - int distance = (int)(r1->rect.width * 0.25 + 0.5); - - return r2->classification.id == r1->classification.id && - r2->rect.x <= r1->rect.x + distance && - r2->rect.x >= r1->rect.x - distance && - r2->rect.y <= r1->rect.y + distance && - r2->rect.y >= r1->rect.y - distance && - r2->rect.width <= (int)(r1->rect.width * 1.5 + 0.5) && - (int)(r2->rect.width * 1.5 + 0.5) >= r1->rect.width; -} - -ccv_array_t* ccv_bbf_detect_objects(ccv_dense_matrix_t* a, ccv_bbf_classifier_cascade_t** _cascade, int count, ccv_bbf_param_t params) -{ - int hr = a->rows / params.size.height; - int wr = a->cols / params.size.width; - double scale = pow(2., 1. / (params.interval + 1.)); - int next = params.interval + 1; - int scale_upto = (int)(log((double)ccv_min(hr, wr)) / log(scale)); - ccv_dense_matrix_t** pyr = (ccv_dense_matrix_t**)alloca((scale_upto + next * 2) * 4 * sizeof(ccv_dense_matrix_t*)); - memset(pyr, 0, (scale_upto + next * 2) * 4 * sizeof(ccv_dense_matrix_t*)); - if (params.size.height != _cascade[0]->size.height || params.size.width != _cascade[0]->size.width) - ccv_resample(a, &pyr[0], 0, a->rows * _cascade[0]->size.height / params.size.height, a->cols * _cascade[0]->size.width / params.size.width, CCV_INTER_AREA); - else - pyr[0] = a; - int i, j, k, t, x, y, q; - for (i = 1; i < ccv_min(params.interval + 1, scale_upto + next * 2); i++) - ccv_resample(pyr[0], &pyr[i * 4], 0, (int)(pyr[0]->rows / pow(scale, i)), (int)(pyr[0]->cols / pow(scale, i)), CCV_INTER_AREA); - for (i = next; i < scale_upto + next * 2; i++) - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4], 0, 0, 0); - if (params.accurate) - for (i = next * 2; i < scale_upto + next * 2; i++) - { - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 1], 0, 1, 0); - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 2], 0, 0, 1); - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 3], 0, 1, 1); - } - ccv_array_t* idx_seq; - ccv_array_t* seq = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - ccv_array_t* seq2 = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - ccv_array_t* result_seq = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - /* detect in multi scale */ - for (t = 0; t < count; t++) - { - ccv_bbf_classifier_cascade_t* cascade = _cascade[t]; - float scale_x = (float) params.size.width / (float) cascade->size.width; - float scale_y = (float) params.size.height / (float) cascade->size.height; - ccv_array_clear(seq); - for (i = 0; i < scale_upto; i++) - { - int dx[] = {0, 1, 0, 1}; - int dy[] = {0, 0, 1, 1}; - int i_rows = pyr[i * 4 + next * 8]->rows - (cascade->size.height >> 2); - int steps[] = { pyr[i * 4]->step, pyr[i * 4 + next * 4]->step, pyr[i * 4 + next * 8]->step }; - int i_cols = pyr[i * 4 + next * 8]->cols - (cascade->size.width >> 2); - int paddings[] = { pyr[i * 4]->step * 4 - i_cols * 4, - pyr[i * 4 + next * 4]->step * 2 - i_cols * 2, - pyr[i * 4 + next * 8]->step - i_cols }; - for (q = 0; q < (params.accurate ? 4 : 1); q++) - { - unsigned char* u8[] = { pyr[i * 4]->data.u8 + dx[q] * 2 + dy[q] * pyr[i * 4]->step * 2, pyr[i * 4 + next * 4]->data.u8 + dx[q] + dy[q] * pyr[i * 4 + next * 4]->step, pyr[i * 4 + next * 8 + q]->data.u8 }; - for (y = 0; y < i_rows; y++) - { - for (x = 0; x < i_cols; x++) - { - float sum; - int flag = 1; - ccv_bbf_stage_classifier_t* classifier = cascade->stage_classifier; - for (j = 0; j < cascade->count; ++j, ++classifier) - { - sum = 0; - float* alpha = classifier->alpha; - ccv_bbf_feature_t* feature = classifier->feature; - for (k = 0; k < classifier->count; ++k, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - if (sum < classifier->threshold) - { - flag = 0; - break; - } - } - if (flag) - { - ccv_comp_t comp; - comp.rect = ccv_rect((int)((x * 4 + dx[q] * 2) * scale_x + 0.5), (int)((y * 4 + dy[q] * 2) * scale_y + 0.5), (int)(cascade->size.width * scale_x + 0.5), (int)(cascade->size.height * scale_y + 0.5)); - comp.neighbors = 1; - comp.classification.id = t; - comp.classification.confidence = sum; - ccv_array_push(seq, &comp); - } - u8[0] += 4; - u8[1] += 2; - u8[2] += 1; - } - u8[0] += paddings[0]; - u8[1] += paddings[1]; - u8[2] += paddings[2]; - } - } - scale_x *= scale; - scale_y *= scale; - } - - /* the following code from OpenCV's haar feature implementation */ - if(params.min_neighbors == 0) - { - for (i = 0; i < seq->rnum; i++) - { - ccv_comp_t* comp = (ccv_comp_t*)ccv_array_get(seq, i); - ccv_array_push(result_seq, comp); - } - } else { - idx_seq = 0; - ccv_array_clear(seq2); - // group retrieved rectangles in order to filter out noise - int ncomp = ccv_array_group(seq, &idx_seq, _ccv_is_equal_same_class, 0); - ccv_comp_t* comps = (ccv_comp_t*)ccmalloc((ncomp + 1) * sizeof(ccv_comp_t)); - memset(comps, 0, (ncomp + 1) * sizeof(ccv_comp_t)); - - // count number of neighbors - for(i = 0; i < seq->rnum; i++) - { - ccv_comp_t r1 = *(ccv_comp_t*)ccv_array_get(seq, i); - int idx = *(int*)ccv_array_get(idx_seq, i); - - if (comps[idx].neighbors == 0) - comps[idx].classification.confidence = r1.classification.confidence; - - ++comps[idx].neighbors; - - comps[idx].rect.x += r1.rect.x; - comps[idx].rect.y += r1.rect.y; - comps[idx].rect.width += r1.rect.width; - comps[idx].rect.height += r1.rect.height; - comps[idx].classification.id = r1.classification.id; - comps[idx].classification.confidence = ccv_max(comps[idx].classification.confidence, r1.classification.confidence); - } - - // calculate average bounding box - for(i = 0; i < ncomp; i++) - { - int n = comps[i].neighbors; - if(n >= params.min_neighbors) - { - ccv_comp_t comp; - comp.rect.x = (comps[i].rect.x * 2 + n) / (2 * n); - comp.rect.y = (comps[i].rect.y * 2 + n) / (2 * n); - comp.rect.width = (comps[i].rect.width * 2 + n) / (2 * n); - comp.rect.height = (comps[i].rect.height * 2 + n) / (2 * n); - comp.neighbors = comps[i].neighbors; - comp.classification.id = comps[i].classification.id; - comp.classification.confidence = comps[i].classification.confidence; - ccv_array_push(seq2, &comp); - } - } - - // filter out small face rectangles inside large face rectangles - for(i = 0; i < seq2->rnum; i++) - { - ccv_comp_t r1 = *(ccv_comp_t*)ccv_array_get(seq2, i); - int flag = 1; - - for(j = 0; j < seq2->rnum; j++) - { - ccv_comp_t r2 = *(ccv_comp_t*)ccv_array_get(seq2, j); - int distance = (int)(r2.rect.width * 0.25 + 0.5); - - if(i != j && - r1.classification.id == r2.classification.id && - r1.rect.x >= r2.rect.x - distance && - r1.rect.y >= r2.rect.y - distance && - r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance && - r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance && - (r2.neighbors > ccv_max(3, r1.neighbors) || r1.neighbors < 3)) - { - flag = 0; - break; - } - } - - if(flag) - ccv_array_push(result_seq, &r1); - } - ccv_array_free(idx_seq); - ccfree(comps); - } - } - - ccv_array_free(seq); - ccv_array_free(seq2); - - ccv_array_t* result_seq2; - /* the following code from OpenCV's haar feature implementation */ - if (params.flags & CCV_BBF_NO_NESTED) - { - result_seq2 = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - idx_seq = 0; - // group retrieved rectangles in order to filter out noise - int ncomp = ccv_array_group(result_seq, &idx_seq, _ccv_is_equal, 0); - ccv_comp_t* comps = (ccv_comp_t*)ccmalloc((ncomp + 1) * sizeof(ccv_comp_t)); - memset(comps, 0, (ncomp + 1) * sizeof(ccv_comp_t)); - - // count number of neighbors - for(i = 0; i < result_seq->rnum; i++) - { - ccv_comp_t r1 = *(ccv_comp_t*)ccv_array_get(result_seq, i); - int idx = *(int*)ccv_array_get(idx_seq, i); - - if (comps[idx].neighbors == 0 || comps[idx].classification.confidence < r1.classification.confidence) - { - comps[idx].classification.confidence = r1.classification.confidence; - comps[idx].neighbors = 1; - comps[idx].rect = r1.rect; - comps[idx].classification.id = r1.classification.id; - } - } - - // calculate average bounding box - for(i = 0; i < ncomp; i++) - if(comps[i].neighbors) - ccv_array_push(result_seq2, &comps[i]); - - ccv_array_free(result_seq); - ccfree(comps); - } else { - result_seq2 = result_seq; - } - - for (i = 1; i < scale_upto + next * 2; i++) - ccv_matrix_free(pyr[i * 4]); - if (params.accurate) - for (i = next * 2; i < scale_upto + next * 2; i++) - { - ccv_matrix_free(pyr[i * 4 + 1]); - ccv_matrix_free(pyr[i * 4 + 2]); - ccv_matrix_free(pyr[i * 4 + 3]); - } - if (params.size.height != _cascade[0]->size.height || params.size.width != _cascade[0]->size.width) - ccv_matrix_free(pyr[0]); - - return result_seq2; -} - -ccv_bbf_classifier_cascade_t* ccv_bbf_read_classifier_cascade(const char* directory) -{ - char buf[1024]; - sprintf(buf, "%s/cascade.txt", directory); - int s, i; - FILE* r = fopen(buf, "r"); - if (r == 0) - return 0; - ccv_bbf_classifier_cascade_t* cascade = (ccv_bbf_classifier_cascade_t*)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); - s = fscanf(r, "%d %d %d", &cascade->count, &cascade->size.width, &cascade->size.height); - assert(s > 0); - cascade->stage_classifier = (ccv_bbf_stage_classifier_t*)ccmalloc(cascade->count * sizeof(ccv_bbf_stage_classifier_t)); - for (i = 0; i < cascade->count; i++) - { - sprintf(buf, "%s/stage-%d.txt", directory, i); - if (_ccv_read_bbf_stage_classifier(buf, &cascade->stage_classifier[i]) < 0) - { - cascade->count = i; - break; - } - } - fclose(r); - return cascade; -} - -ccv_bbf_classifier_cascade_t* ccv_bbf_classifier_cascade_read_binary(char* s) -{ - int i; - ccv_bbf_classifier_cascade_t* cascade = (ccv_bbf_classifier_cascade_t*)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); - memcpy(&cascade->count, s, sizeof(cascade->count)); s += sizeof(cascade->count); - memcpy(&cascade->size.width, s, sizeof(cascade->size.width)); s += sizeof(cascade->size.width); - memcpy(&cascade->size.height, s, sizeof(cascade->size.height)); s += sizeof(cascade->size.height); - ccv_bbf_stage_classifier_t* classifier = cascade->stage_classifier = (ccv_bbf_stage_classifier_t*)ccmalloc(cascade->count * sizeof(ccv_bbf_stage_classifier_t)); - for (i = 0; i < cascade->count; i++, classifier++) - { - memcpy(&classifier->count, s, sizeof(classifier->count)); s += sizeof(classifier->count); - memcpy(&classifier->threshold, s, sizeof(classifier->threshold)); s += sizeof(classifier->threshold); - classifier->feature = (ccv_bbf_feature_t*)ccmalloc(classifier->count * sizeof(ccv_bbf_feature_t)); - classifier->alpha = (float*)ccmalloc(classifier->count * 2 * sizeof(float)); - memcpy(classifier->feature, s, classifier->count * sizeof(ccv_bbf_feature_t)); s += classifier->count * sizeof(ccv_bbf_feature_t); - memcpy(classifier->alpha, s, classifier->count * 2 * sizeof(float)); s += classifier->count * 2 * sizeof(float); - } - return cascade; - -} - -int ccv_bbf_classifier_cascade_write_binary(ccv_bbf_classifier_cascade_t* cascade, char* s, int slen) -{ - int i; - int len = sizeof(cascade->count) + sizeof(cascade->size.width) + sizeof(cascade->size.height); - ccv_bbf_stage_classifier_t* classifier = cascade->stage_classifier; - for (i = 0; i < cascade->count; i++, classifier++) - len += sizeof(classifier->count) + sizeof(classifier->threshold) + classifier->count * sizeof(ccv_bbf_feature_t) + classifier->count * 2 * sizeof(float); - if (slen >= len) - { - memcpy(s, &cascade->count, sizeof(cascade->count)); s += sizeof(cascade->count); - memcpy(s, &cascade->size.width, sizeof(cascade->size.width)); s += sizeof(cascade->size.width); - memcpy(s, &cascade->size.height, sizeof(cascade->size.height)); s += sizeof(cascade->size.height); - classifier = cascade->stage_classifier; - for (i = 0; i < cascade->count; i++, classifier++) - { - memcpy(s, &classifier->count, sizeof(classifier->count)); s += sizeof(classifier->count); - memcpy(s, &classifier->threshold, sizeof(classifier->threshold)); s += sizeof(classifier->threshold); - memcpy(s, classifier->feature, classifier->count * sizeof(ccv_bbf_feature_t)); s += classifier->count * sizeof(ccv_bbf_feature_t); - memcpy(s, classifier->alpha, classifier->count * 2 * sizeof(float)); s += classifier->count * 2 * sizeof(float); - } - } - return len; -} - -void ccv_bbf_classifier_cascade_free(ccv_bbf_classifier_cascade_t* cascade) -{ - int i; - for (i = 0; i < cascade->count; ++i) - { - ccfree(cascade->stage_classifier[i].feature); - ccfree(cascade->stage_classifier[i].alpha); - } - ccfree(cascade->stage_classifier); - ccfree(cascade); -} \ No newline at end of file +#ifdef HAVE_GSL \ No newline at end of file diff --git a/test/source.cc b/test/source.cc index f0094b3..644923c 100644 --- a/test/source.cc +++ b/test/source.cc @@ -58,1516 +58,3 @@ static inline int _ccv_run_bbf_feature(ccv_bbf_feature_t *feature, int *step, un #undef nf_at return 1; } - -static int _ccv_read_bbf_stage_classifier(const char *file, ccv_bbf_stage_classifier_t *classifier) -{ - FILE *r = fopen(file, "r"); - if (r == 0) - return -1; - int stat = 0; - stat |= fscanf(r, "%d", &classifier->count); - union { - float fl; - int i; - } fli; - stat |= fscanf(r, "%d", &fli.i); - classifier->threshold = fli.fl; - classifier->feature = (ccv_bbf_feature_t *)ccmalloc(classifier->count * sizeof(ccv_bbf_feature_t)); - classifier->alpha = (float *)ccmalloc(classifier->count * 2 * sizeof(float)); - int i, j; - for (i = 0; i < classifier->count; i++) - { - stat |= fscanf(r, "%d", &classifier->feature[i].size); - for (j = 0; j < classifier->feature[i].size; j++) - { - stat |= fscanf(r, "%d %d %d", &classifier->feature[i].px[j], &classifier->feature[i].py[j], &classifier->feature[i].pz[j]); - stat |= fscanf(r, "%d %d %d", &classifier->feature[i].nx[j], &classifier->feature[i].ny[j], &classifier->feature[i].nz[j]); - } - union { - float fl; - int i; - } flia, flib; - stat |= fscanf(r, "%d %d", &flia.i, &flib.i); - classifier->alpha[i * 2] = flia.fl; - classifier->alpha[i * 2 + 1] = flib.fl; - } - fclose(r); - return 0; -} - -#ifdef HAVE_GSL - -static unsigned int _ccv_bbf_time_measure() -{ - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec * 1000000 + tv.tv_usec; -} - -#define less_than(a, b, aux) ((a) < (b)) -CCV_IMPLEMENT_QSORT(_ccv_sort_32f, float, less_than) -#undef less_than - -static void _ccv_bbf_eval_data(ccv_bbf_stage_classifier_t *classifier, unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, ccv_size_t size, float *peval, float *neval) -{ - int i, j; - int steps[] = {_ccv_width_padding(size.width), - _ccv_width_padding(size.width >> 1), - _ccv_width_padding(size.width >> 2)}; - int isizs0 = steps[0] * size.height; - int isizs01 = isizs0 + steps[1] * (size.height >> 1); - for (i = 0; i < posnum; i++) - { - unsigned char *u8[] = {posdata[i], posdata[i] + isizs0, posdata[i] + isizs01}; - float sum = 0; - float *alpha = classifier->alpha; - ccv_bbf_feature_t *feature = classifier->feature; - for (j = 0; j < classifier->count; ++j, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - peval[i] = sum; - } - for (i = 0; i < negnum; i++) - { - unsigned char *u8[] = {negdata[i], negdata[i] + isizs0, negdata[i] + isizs01}; - float sum = 0; - float *alpha = classifier->alpha; - ccv_bbf_feature_t *feature = classifier->feature; - for (j = 0; j < classifier->count; ++j, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - neval[i] = sum; - } -} - -static int _ccv_prune_positive_data(ccv_bbf_classifier_cascade_t *cascade, unsigned char **posdata, int posnum, ccv_size_t size) -{ - float *peval = (float *)ccmalloc(posnum * sizeof(float)); - int i, j, k, rpos = posnum; - for (i = 0; i < cascade->count; i++) - { - _ccv_bbf_eval_data(cascade->stage_classifier + i, posdata, rpos, 0, 0, size, peval, 0); - k = 0; - for (j = 0; j < rpos; j++) - if (peval[j] >= cascade->stage_classifier[i].threshold) - { - posdata[k] = posdata[j]; - ++k; - } - else - { - ccfree(posdata[j]); - } - rpos = k; - } - ccfree(peval); - return rpos; -} - -static int _ccv_prepare_background_data(ccv_bbf_classifier_cascade_t *cascade, char **bgfiles, int bgnum, unsigned char **negdata, int negnum) -{ - int t, i, j, k, q; - int negperbg; - int negtotal = 0; - int steps[] = {_ccv_width_padding(cascade->size.width), - _ccv_width_padding(cascade->size.width >> 1), - _ccv_width_padding(cascade->size.width >> 2)}; - int isizs0 = steps[0] * cascade->size.height; - int isizs1 = steps[1] * (cascade->size.height >> 1); - int isizs2 = steps[2] * (cascade->size.height >> 2); - int *idcheck = (int *)ccmalloc(negnum * sizeof(int)); - - gsl_rng_env_setup(); - - gsl_rng *rng = gsl_rng_alloc(gsl_rng_default); - gsl_rng_set(rng, (unsigned long int)idcheck); - - ccv_size_t imgsz = cascade->size; - int rneg = negtotal; - for (t = 0; negtotal < negnum; t++) - { - PRINT(CCV_CLI_INFO, "preparing negative data ... 0%%"); - for (i = 0; i < bgnum; i++) - { - negperbg = (t < 2) ? (negnum - negtotal) / (bgnum - i) + 1 : negnum - negtotal; - ccv_dense_matrix_t *image = 0; - ccv_read(bgfiles[i], &image, CCV_IO_GRAY | CCV_IO_ANY_FILE); - assert((image->type & CCV_C1) && (image->type & CCV_8U)); - if (image == 0) - { - PRINT(CCV_CLI_ERROR, "\n%s file corrupted\n", bgfiles[i]); - continue; - } - if (t % 2 != 0) - ccv_flip(image, 0, 0, CCV_FLIP_X); - if (t % 4 >= 2) - ccv_flip(image, 0, 0, CCV_FLIP_Y); - ccv_bbf_param_t params = {.interval = 3, .min_neighbors = 0, .accurate = 1, .flags = 0, .size = cascade->size}; - ccv_array_t *detected = ccv_bbf_detect_objects(image, &cascade, 1, params); - memset(idcheck, 0, ccv_min(detected->rnum, negperbg) * sizeof(int)); - for (j = 0; j < ccv_min(detected->rnum, negperbg); j++) - { - int r = gsl_rng_uniform_int(rng, detected->rnum); - int flag = 1; - ccv_rect_t *rect = (ccv_rect_t *)ccv_array_get(detected, r); - while (flag) - { - flag = 0; - for (k = 0; k < j; k++) - if (r == idcheck[k]) - { - flag = 1; - r = gsl_rng_uniform_int(rng, detected->rnum); - break; - } - rect = (ccv_rect_t *)ccv_array_get(detected, r); - if ((rect->x < 0) || (rect->y < 0) || (rect->width + rect->x > image->cols) || (rect->height + rect->y > image->rows)) - { - flag = 1; - r = gsl_rng_uniform_int(rng, detected->rnum); - } - } - idcheck[j] = r; - ccv_dense_matrix_t *temp = 0; - ccv_dense_matrix_t *imgs0 = 0; - ccv_dense_matrix_t *imgs1 = 0; - ccv_dense_matrix_t *imgs2 = 0; - ccv_slice(image, (ccv_matrix_t **)&temp, 0, rect->y, rect->x, rect->height, rect->width); - ccv_resample(temp, &imgs0, 0, imgsz.height, imgsz.width, CCV_INTER_AREA); - assert(imgs0->step == steps[0]); - ccv_matrix_free(temp); - ccv_sample_down(imgs0, &imgs1, 0, 0, 0); - assert(imgs1->step == steps[1]); - ccv_sample_down(imgs1, &imgs2, 0, 0, 0); - assert(imgs2->step == steps[2]); - - negdata[negtotal] = (unsigned char *)ccmalloc(isizs0 + isizs1 + isizs2); - unsigned char *u8s0 = negdata[negtotal]; - unsigned char *u8s1 = negdata[negtotal] + isizs0; - unsigned char *u8s2 = negdata[negtotal] + isizs0 + isizs1; - unsigned char *u8[] = {u8s0, u8s1, u8s2}; - memcpy(u8s0, imgs0->data.u8, imgs0->rows * imgs0->step); - ccv_matrix_free(imgs0); - memcpy(u8s1, imgs1->data.u8, imgs1->rows * imgs1->step); - ccv_matrix_free(imgs1); - memcpy(u8s2, imgs2->data.u8, imgs2->rows * imgs2->step); - ccv_matrix_free(imgs2); - - flag = 1; - ccv_bbf_stage_classifier_t *classifier = cascade->stage_classifier; - for (k = 0; k < cascade->count; ++k, ++classifier) - { - float sum = 0; - float *alpha = classifier->alpha; - ccv_bbf_feature_t *feature = classifier->feature; - for (q = 0; q < classifier->count; ++q, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - if (sum < classifier->threshold) - { - flag = 0; - break; - } - } - if (!flag) - ccfree(negdata[negtotal]); - else - { - ++negtotal; - if (negtotal >= negnum) - break; - } - } - ccv_array_free(detected); - ccv_matrix_free(image); - ccv_drain_cache(); - PRINT(CCV_CLI_INFO, "\rpreparing negative data ... %2d%%", 100 * negtotal / negnum); - fflush(0); - if (negtotal >= negnum) - break; - } - if (rneg == negtotal) - break; - rneg = negtotal; - PRINT(CCV_CLI_INFO, "\nentering additional round %d\n", t + 1); - } - gsl_rng_free(rng); - ccfree(idcheck); - ccv_drain_cache(); - PRINT(CCV_CLI_INFO, "\n"); - return negtotal; -} - -static void _ccv_prepare_positive_data(ccv_dense_matrix_t **posimg, unsigned char **posdata, ccv_size_t size, int posnum) -{ - PRINT(CCV_CLI_INFO, "preparing positive data ... 0%%"); - int i; - for (i = 0; i < posnum; i++) - { - ccv_dense_matrix_t *imgs0 = posimg[i]; - ccv_dense_matrix_t *imgs1 = 0; - ccv_dense_matrix_t *imgs2 = 0; - assert((imgs0->type & CCV_C1) && (imgs0->type & CCV_8U) && imgs0->rows == size.height && imgs0->cols == size.width); - ccv_sample_down(imgs0, &imgs1, 0, 0, 0); - ccv_sample_down(imgs1, &imgs2, 0, 0, 0); - int isizs0 = imgs0->rows * imgs0->step; - int isizs1 = imgs1->rows * imgs1->step; - int isizs2 = imgs2->rows * imgs2->step; - - posdata[i] = (unsigned char *)ccmalloc(isizs0 + isizs1 + isizs2); - memcpy(posdata[i], imgs0->data.u8, isizs0); - memcpy(posdata[i] + isizs0, imgs1->data.u8, isizs1); - memcpy(posdata[i] + isizs0 + isizs1, imgs2->data.u8, isizs2); - - PRINT(CCV_CLI_INFO, "\rpreparing positive data ... %2d%%", 100 * (i + 1) / posnum); - fflush(0); - - ccv_matrix_free(imgs1); - ccv_matrix_free(imgs2); - } - ccv_drain_cache(); - PRINT(CCV_CLI_INFO, "\n"); -} - -typedef struct -{ - double fitness; - int pk, nk; - int age; - double error; - ccv_bbf_feature_t feature; -} ccv_bbf_gene_t; - -static inline void _ccv_bbf_genetic_fitness(ccv_bbf_gene_t *gene) -{ - gene->fitness = (1 - gene->error) * exp(-0.01 * gene->age) * exp((gene->pk + gene->nk) * log(1.015)); -} - -static inline int _ccv_bbf_exist_gene_feature(ccv_bbf_gene_t *gene, int x, int y, int z) -{ - int i; - for (i = 0; i < gene->pk; i++) - if (z == gene->feature.pz[i] && x == gene->feature.px[i] && y == gene->feature.py[i]) - return 1; - for (i = 0; i < gene->nk; i++) - if (z == gene->feature.nz[i] && x == gene->feature.nx[i] && y == gene->feature.ny[i]) - return 1; - return 0; -} - -static inline void _ccv_bbf_randomize_gene(gsl_rng *rng, ccv_bbf_gene_t *gene, int *rows, int *cols) -{ - int i; - do - { - gene->pk = gsl_rng_uniform_int(rng, CCV_BBF_POINT_MAX - 1) + 1; - gene->nk = gsl_rng_uniform_int(rng, CCV_BBF_POINT_MAX - 1) + 1; - } while (gene->pk + gene->nk < CCV_BBF_POINT_MIN); /* a hard restriction of at least 3 points have to be examed */ - gene->feature.size = ccv_max(gene->pk, gene->nk); - gene->age = 0; - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - { - gene->feature.pz[i] = -1; - gene->feature.nz[i] = -1; - } - int x, y, z; - for (i = 0; i < gene->pk; i++) - { - do - { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(gene, x, y, z)); - gene->feature.pz[i] = z; - gene->feature.px[i] = x; - gene->feature.py[i] = y; - } - for (i = 0; i < gene->nk; i++) - { - do - { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(gene, x, y, z)); - gene->feature.nz[i] = z; - gene->feature.nx[i] = x; - gene->feature.ny[i] = y; - } -} - -static inline double _ccv_bbf_error_rate(ccv_bbf_feature_t *feature, unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, ccv_size_t size, double *pw, double *nw) -{ - int i; - int steps[] = {_ccv_width_padding(size.width), - _ccv_width_padding(size.width >> 1), - _ccv_width_padding(size.width >> 2)}; - int isizs0 = steps[0] * size.height; - int isizs01 = isizs0 + steps[1] * (size.height >> 1); - double error = 0; - for (i = 0; i < posnum; i++) - { - unsigned char *u8[] = {posdata[i], posdata[i] + isizs0, posdata[i] + isizs01}; - if (!_ccv_run_bbf_feature(feature, steps, u8)) - error += pw[i]; - } - for (i = 0; i < negnum; i++) - { - unsigned char *u8[] = {negdata[i], negdata[i] + isizs0, negdata[i] + isizs01}; - if (_ccv_run_bbf_feature(feature, steps, u8)) - error += nw[i]; - } - return error; -} - -#define less_than(fit1, fit2, aux) ((fit1).fitness >= (fit2).fitness) -static CCV_IMPLEMENT_QSORT(_ccv_bbf_genetic_qsort, ccv_bbf_gene_t, less_than) -#undef less_than - - static ccv_bbf_feature_t _ccv_bbf_genetic_optimize(unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, int ftnum, ccv_size_t size, double *pw, double *nw) -{ - ccv_bbf_feature_t best; - /* seed (random method) */ - gsl_rng_env_setup(); - gsl_rng *rng = gsl_rng_alloc(gsl_rng_default); - union { - unsigned long int li; - double db; - } dbli; - dbli.db = pw[0] + nw[0]; - gsl_rng_set(rng, dbli.li); - int i, j; - int pnum = ftnum * 100; - assert(pnum > 0); - ccv_bbf_gene_t *gene = (ccv_bbf_gene_t *)ccmalloc(pnum * sizeof(ccv_bbf_gene_t)); - int rows[] = {size.height, size.height >> 1, size.height >> 2}; - int cols[] = {size.width, size.width >> 1, size.width >> 2}; - for (i = 0; i < pnum; i++) - _ccv_bbf_randomize_gene(rng, &gene[i], rows, cols); - unsigned int timer = _ccv_bbf_time_measure(); -#ifdef USE_OPENMP -#pragma omp parallel for private(i) schedule(dynamic) -#endif - for (i = 0; i < pnum; i++) - gene[i].error = _ccv_bbf_error_rate(&gene[i].feature, posdata, posnum, negdata, negnum, size, pw, nw); - timer = _ccv_bbf_time_measure() - timer; - for (i = 0; i < pnum; i++) - _ccv_bbf_genetic_fitness(&gene[i]); - double best_err = 1; - int rnum = ftnum * 39; /* number of randomize */ - int mnum = ftnum * 40; /* number of mutation */ - int hnum = ftnum * 20; /* number of hybrid */ - /* iteration stop crit : best no change in 40 iterations */ - int it = 0, t; - for (t = 0; it < 40; ++it, ++t) - { - int min_id = 0; - double min_err = gene[0].error; - for (i = 1; i < pnum; i++) - if (gene[i].error < min_err) - { - min_id = i; - min_err = gene[i].error; - } - min_err = gene[min_id].error = _ccv_bbf_error_rate(&gene[min_id].feature, posdata, posnum, negdata, negnum, size, pw, nw); - if (min_err < best_err) - { - best_err = min_err; - memcpy(&best, &gene[min_id].feature, sizeof(best)); - PRINT(CCV_CLI_INFO, "best bbf feature with error %f\n|-size: %d\n|-positive point: ", best_err, best.size); - for (i = 0; i < best.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", best.px[i], best.py[i], best.pz[i]); - PRINT(CCV_CLI_INFO, "\n|-negative point: "); - for (i = 0; i < best.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", best.nx[i], best.ny[i], best.nz[i]); - PRINT(CCV_CLI_INFO, "\n"); - it = 0; - } - PRINT(CCV_CLI_INFO, "minimum error achieved in round %d(%d) : %f with %d ms\n", t, it, min_err, timer / 1000); - _ccv_bbf_genetic_qsort(gene, pnum, 0); - for (i = 0; i < ftnum; i++) - ++gene[i].age; - for (i = ftnum; i < ftnum + mnum; i++) - { - int parent = gsl_rng_uniform_int(rng, ftnum); - memcpy(gene + i, gene + parent, sizeof(ccv_bbf_gene_t)); - /* three mutation strategy : 1. add, 2. remove, 3. refine */ - int pnm, pn = gsl_rng_uniform_int(rng, 2); - int *pnk[] = {&gene[i].pk, &gene[i].nk}; - int *pnx[] = {gene[i].feature.px, gene[i].feature.nx}; - int *pny[] = {gene[i].feature.py, gene[i].feature.ny}; - int *pnz[] = {gene[i].feature.pz, gene[i].feature.nz}; - int x, y, z; - int victim, decay = 1; - do - { - switch (gsl_rng_uniform_int(rng, 3)) - { - case 0: /* add */ - if (gene[i].pk == CCV_BBF_POINT_MAX && gene[i].nk == CCV_BBF_POINT_MAX) - break; - while (*pnk[pn] + 1 > CCV_BBF_POINT_MAX) - pn = gsl_rng_uniform_int(rng, 2); - do - { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(&gene[i], x, y, z)); - pnz[pn][*pnk[pn]] = z; - pnx[pn][*pnk[pn]] = x; - pny[pn][*pnk[pn]] = y; - ++(*pnk[pn]); - gene[i].feature.size = ccv_max(gene[i].pk, gene[i].nk); - decay = gene[i].age = 0; - break; - case 1: /* remove */ - if (gene[i].pk + gene[i].nk <= CCV_BBF_POINT_MIN) /* at least 3 points have to be examed */ - break; - while (*pnk[pn] - 1 <= 0) // || *pnk[pn] + *pnk[!pn] - 1 < CCV_BBF_POINT_MIN) - pn = gsl_rng_uniform_int(rng, 2); - victim = gsl_rng_uniform_int(rng, *pnk[pn]); - for (j = victim; j < *pnk[pn] - 1; j++) - { - pnz[pn][j] = pnz[pn][j + 1]; - pnx[pn][j] = pnx[pn][j + 1]; - pny[pn][j] = pny[pn][j + 1]; - } - pnz[pn][*pnk[pn] - 1] = -1; - --(*pnk[pn]); - gene[i].feature.size = ccv_max(gene[i].pk, gene[i].nk); - decay = gene[i].age = 0; - break; - case 2: /* refine */ - pnm = gsl_rng_uniform_int(rng, *pnk[pn]); - do - { - z = gsl_rng_uniform_int(rng, 3); - x = gsl_rng_uniform_int(rng, cols[z]); - y = gsl_rng_uniform_int(rng, rows[z]); - } while (_ccv_bbf_exist_gene_feature(&gene[i], x, y, z)); - pnz[pn][pnm] = z; - pnx[pn][pnm] = x; - pny[pn][pnm] = y; - decay = gene[i].age = 0; - break; - } - } while (decay); - } - for (i = ftnum + mnum; i < ftnum + mnum + hnum; i++) - { - /* hybrid strategy: taking positive points from dad, negative points from mum */ - int dad, mum; - do - { - dad = gsl_rng_uniform_int(rng, ftnum); - mum = gsl_rng_uniform_int(rng, ftnum); - } while (dad == mum || gene[dad].pk + gene[mum].nk < CCV_BBF_POINT_MIN); /* at least 3 points have to be examed */ - for (j = 0; j < CCV_BBF_POINT_MAX; j++) - { - gene[i].feature.pz[j] = -1; - gene[i].feature.nz[j] = -1; - } - gene[i].pk = gene[dad].pk; - for (j = 0; j < gene[i].pk; j++) - { - gene[i].feature.pz[j] = gene[dad].feature.pz[j]; - gene[i].feature.px[j] = gene[dad].feature.px[j]; - gene[i].feature.py[j] = gene[dad].feature.py[j]; - } - gene[i].nk = gene[mum].nk; - for (j = 0; j < gene[i].nk; j++) - { - gene[i].feature.nz[j] = gene[mum].feature.nz[j]; - gene[i].feature.nx[j] = gene[mum].feature.nx[j]; - gene[i].feature.ny[j] = gene[mum].feature.ny[j]; - } - gene[i].feature.size = ccv_max(gene[i].pk, gene[i].nk); - gene[i].age = 0; - } - for (i = ftnum + mnum + hnum; i < ftnum + mnum + hnum + rnum; i++) - _ccv_bbf_randomize_gene(rng, &gene[i], rows, cols); - timer = _ccv_bbf_time_measure(); -#ifdef USE_OPENMP -#pragma omp parallel for private(i) schedule(dynamic) -#endif - for (i = 0; i < pnum; i++) - gene[i].error = _ccv_bbf_error_rate(&gene[i].feature, posdata, posnum, negdata, negnum, size, pw, nw); - timer = _ccv_bbf_time_measure() - timer; - for (i = 0; i < pnum; i++) - _ccv_bbf_genetic_fitness(&gene[i]); - } - ccfree(gene); - gsl_rng_free(rng); - return best; -} - -#define less_than(fit1, fit2, aux) ((fit1).error < (fit2).error) -static CCV_IMPLEMENT_QSORT(_ccv_bbf_best_qsort, ccv_bbf_gene_t, less_than) -#undef less_than - - static ccv_bbf_gene_t _ccv_bbf_best_gene(ccv_bbf_gene_t *gene, int pnum, int point_min, unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, ccv_size_t size, double *pw, double *nw) -{ - int i; - unsigned int timer = _ccv_bbf_time_measure(); -#ifdef USE_OPENMP -#pragma omp parallel for private(i) schedule(dynamic) -#endif - for (i = 0; i < pnum; i++) - gene[i].error = _ccv_bbf_error_rate(&gene[i].feature, posdata, posnum, negdata, negnum, size, pw, nw); - timer = _ccv_bbf_time_measure() - timer; - _ccv_bbf_best_qsort(gene, pnum, 0); - int min_id = 0; - double min_err = gene[0].error; - for (i = 0; i < pnum; i++) - if (gene[i].nk + gene[i].pk >= point_min) - { - min_id = i; - min_err = gene[i].error; - break; - } - PRINT(CCV_CLI_INFO, "local best bbf feature with error %f\n|-size: %d\n|-positive point: ", min_err, gene[min_id].feature.size); - for (i = 0; i < gene[min_id].feature.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", gene[min_id].feature.px[i], gene[min_id].feature.py[i], gene[min_id].feature.pz[i]); - PRINT(CCV_CLI_INFO, "\n|-negative point: "); - for (i = 0; i < gene[min_id].feature.size; i++) - PRINT(CCV_CLI_INFO, "(%d %d %d), ", gene[min_id].feature.nx[i], gene[min_id].feature.ny[i], gene[min_id].feature.nz[i]); - PRINT(CCV_CLI_INFO, "\nthe computation takes %d ms\n", timer / 1000); - return gene[min_id]; -} - -static ccv_bbf_feature_t _ccv_bbf_convex_optimize(unsigned char **posdata, int posnum, unsigned char **negdata, int negnum, ccv_bbf_feature_t *best_feature, ccv_size_t size, double *pw, double *nw) -{ - ccv_bbf_gene_t best_gene; - /* seed (random method) */ - gsl_rng_env_setup(); - gsl_rng *rng = gsl_rng_alloc(gsl_rng_default); - union { - unsigned long int li; - double db; - } dbli; - dbli.db = pw[0] + nw[0]; - gsl_rng_set(rng, dbli.li); - int i, j, k, q, p, g, t; - int rows[] = {size.height, size.height >> 1, size.height >> 2}; - int cols[] = {size.width, size.width >> 1, size.width >> 2}; - int pnum = rows[0] * cols[0] + rows[1] * cols[1] + rows[2] * cols[2]; - ccv_bbf_gene_t *gene = (ccv_bbf_gene_t *)ccmalloc((pnum * (CCV_BBF_POINT_MAX * 2 + 1) * 2 + CCV_BBF_POINT_MAX * 2 + 1) * sizeof(ccv_bbf_gene_t)); - if (best_feature == 0) - { - /* bootstrapping the best feature, start from two pixels, one for positive, one for negative - * the bootstrapping process go like this: first, it will assign a random pixel as positive - * and enumerate every possible pixel as negative, and pick the best one. Then, enumerate every - * possible pixel as positive, and pick the best one, until it converges */ - memset(&best_gene, 0, sizeof(ccv_bbf_gene_t)); - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - best_gene.feature.pz[i] = best_gene.feature.nz[i] = -1; - best_gene.pk = 1; - best_gene.nk = 0; - best_gene.feature.size = 1; - best_gene.feature.pz[0] = gsl_rng_uniform_int(rng, 3); - best_gene.feature.px[0] = gsl_rng_uniform_int(rng, cols[best_gene.feature.pz[0]]); - best_gene.feature.py[0] = gsl_rng_uniform_int(rng, rows[best_gene.feature.pz[0]]); - for (t = 0;; ++t) - { - g = 0; - if (t % 2 == 0) - { - for (i = 0; i < 3; i++) - for (j = 0; j < cols[i]; j++) - for (k = 0; k < rows[i]; k++) - if (i != best_gene.feature.pz[0] || j != best_gene.feature.px[0] || k != best_gene.feature.py[0]) - { - gene[g] = best_gene; - gene[g].pk = gene[g].nk = 1; - gene[g].feature.nz[0] = i; - gene[g].feature.nx[0] = j; - gene[g].feature.ny[0] = k; - g++; - } - } - else - { - for (i = 0; i < 3; i++) - for (j = 0; j < cols[i]; j++) - for (k = 0; k < rows[i]; k++) - if (i != best_gene.feature.nz[0] || j != best_gene.feature.nx[0] || k != best_gene.feature.ny[0]) - { - gene[g] = best_gene; - gene[g].pk = gene[g].nk = 1; - gene[g].feature.pz[0] = i; - gene[g].feature.px[0] = j; - gene[g].feature.py[0] = k; - g++; - } - } - PRINT(CCV_CLI_INFO, "bootstrapping round : %d\n", t); - ccv_bbf_gene_t local_gene = _ccv_bbf_best_gene(gene, g, 2, posdata, posnum, negdata, negnum, size, pw, nw); - if (local_gene.error >= best_gene.error - 1e-10) - break; - best_gene = local_gene; - } - } - else - { - best_gene.feature = *best_feature; - best_gene.pk = best_gene.nk = best_gene.feature.size; - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - if (best_feature->pz[i] == -1) - { - best_gene.pk = i; - break; - } - for (i = 0; i < CCV_BBF_POINT_MAX; i++) - if (best_feature->nz[i] == -1) - { - best_gene.nk = i; - break; - } - } - /* after bootstrapping, the float search technique will do the following permutations: - * a). add a new point to positive or negative - * b). remove a point from positive or negative - * c). move an existing point in positive or negative to another position - * the three rules applied exhaustively, no heuristic used. */ - for (t = 0;; ++t) - { - g = 0; - for (i = 0; i < 3; i++) - for (j = 0; j < cols[i]; j++) - for (k = 0; k < rows[i]; k++) - if (!_ccv_bbf_exist_gene_feature(&best_gene, j, k, i)) - { - /* add positive point */ - if (best_gene.pk < CCV_BBF_POINT_MAX - 1) - { - gene[g] = best_gene; - gene[g].feature.pz[gene[g].pk] = i; - gene[g].feature.px[gene[g].pk] = j; - gene[g].feature.py[gene[g].pk] = k; - gene[g].pk++; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - /* add negative point */ - if (best_gene.nk < CCV_BBF_POINT_MAX - 1) - { - gene[g] = best_gene; - gene[g].feature.nz[gene[g].nk] = i; - gene[g].feature.nx[gene[g].nk] = j; - gene[g].feature.ny[gene[g].nk] = k; - gene[g].nk++; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - /* refine positive point */ - for (q = 0; q < best_gene.pk; q++) - { - gene[g] = best_gene; - gene[g].feature.pz[q] = i; - gene[g].feature.px[q] = j; - gene[g].feature.py[q] = k; - g++; - } - /* add positive point, remove negative point */ - if (best_gene.pk < CCV_BBF_POINT_MAX - 1 && best_gene.nk > 1) - { - for (q = 0; q < best_gene.nk; q++) - { - gene[g] = best_gene; - gene[g].feature.pz[gene[g].pk] = i; - gene[g].feature.px[gene[g].pk] = j; - gene[g].feature.py[gene[g].pk] = k; - gene[g].pk++; - for (p = q; p < best_gene.nk - 1; p++) - { - gene[g].feature.nz[p] = gene[g].feature.nz[p + 1]; - gene[g].feature.nx[p] = gene[g].feature.nx[p + 1]; - gene[g].feature.ny[p] = gene[g].feature.ny[p + 1]; - } - gene[g].feature.nz[gene[g].nk - 1] = -1; - gene[g].nk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - } - /* refine negative point */ - for (q = 0; q < best_gene.nk; q++) - { - gene[g] = best_gene; - gene[g].feature.nz[q] = i; - gene[g].feature.nx[q] = j; - gene[g].feature.ny[q] = k; - g++; - } - /* add negative point, remove positive point */ - if (best_gene.pk > 1 && best_gene.nk < CCV_BBF_POINT_MAX - 1) - { - for (q = 0; q < best_gene.pk; q++) - { - gene[g] = best_gene; - gene[g].feature.nz[gene[g].nk] = i; - gene[g].feature.nx[gene[g].nk] = j; - gene[g].feature.ny[gene[g].nk] = k; - gene[g].nk++; - for (p = q; p < best_gene.pk - 1; p++) - { - gene[g].feature.pz[p] = gene[g].feature.pz[p + 1]; - gene[g].feature.px[p] = gene[g].feature.px[p + 1]; - gene[g].feature.py[p] = gene[g].feature.py[p + 1]; - } - gene[g].feature.pz[gene[g].pk - 1] = -1; - gene[g].pk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - } - } - if (best_gene.pk > 1) - for (q = 0; q < best_gene.pk; q++) - { - gene[g] = best_gene; - for (i = q; i < best_gene.pk - 1; i++) - { - gene[g].feature.pz[i] = gene[g].feature.pz[i + 1]; - gene[g].feature.px[i] = gene[g].feature.px[i + 1]; - gene[g].feature.py[i] = gene[g].feature.py[i + 1]; - } - gene[g].feature.pz[gene[g].pk - 1] = -1; - gene[g].pk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - if (best_gene.nk > 1) - for (q = 0; q < best_gene.nk; q++) - { - gene[g] = best_gene; - for (i = q; i < best_gene.nk - 1; i++) - { - gene[g].feature.nz[i] = gene[g].feature.nz[i + 1]; - gene[g].feature.nx[i] = gene[g].feature.nx[i + 1]; - gene[g].feature.ny[i] = gene[g].feature.ny[i + 1]; - } - gene[g].feature.nz[gene[g].nk - 1] = -1; - gene[g].nk--; - gene[g].feature.size = ccv_max(gene[g].pk, gene[g].nk); - g++; - } - gene[g] = best_gene; - g++; - PRINT(CCV_CLI_INFO, "float search round : %d\n", t); - ccv_bbf_gene_t local_gene = _ccv_bbf_best_gene(gene, g, CCV_BBF_POINT_MIN, posdata, posnum, negdata, negnum, size, pw, nw); - if (local_gene.error >= best_gene.error - 1e-10) - break; - best_gene = local_gene; - } - ccfree(gene); - gsl_rng_free(rng); - return best_gene.feature; -} - -static int _ccv_write_bbf_stage_classifier(const char *file, ccv_bbf_stage_classifier_t *classifier) -{ - FILE *w = fopen(file, "wb"); - if (w == 0) - return -1; - fprintf(w, "%d\n", classifier->count); - union { - float fl; - int i; - } fli; - fli.fl = classifier->threshold; - fprintf(w, "%d\n", fli.i); - int i, j; - for (i = 0; i < classifier->count; i++) - { - fprintf(w, "%d\n", classifier->feature[i].size); - for (j = 0; j < classifier->feature[i].size; j++) - { - fprintf(w, "%d %d %d\n", classifier->feature[i].px[j], classifier->feature[i].py[j], classifier->feature[i].pz[j]); - fprintf(w, "%d %d %d\n", classifier->feature[i].nx[j], classifier->feature[i].ny[j], classifier->feature[i].nz[j]); - } - union { - float fl; - int i; - } flia, flib; - flia.fl = classifier->alpha[i * 2]; - flib.fl = classifier->alpha[i * 2 + 1]; - fprintf(w, "%d %d\n", flia.i, flib.i); - } - fclose(w); - return 0; -} - -static int _ccv_read_background_data(const char *file, unsigned char **negdata, int *negnum, ccv_size_t size) -{ - int stat = 0; - FILE *r = fopen(file, "rb"); - if (r == 0) - return -1; - stat |= fread(negnum, sizeof(int), 1, r); - int i; - int isizs012 = _ccv_width_padding(size.width) * size.height + - _ccv_width_padding(size.width >> 1) * (size.height >> 1) + - _ccv_width_padding(size.width >> 2) * (size.height >> 2); - for (i = 0; i < *negnum; i++) - { - negdata[i] = (unsigned char *)ccmalloc(isizs012); - stat |= fread(negdata[i], 1, isizs012, r); - } - fclose(r); - return 0; -} - -static int _ccv_write_background_data(const char *file, unsigned char **negdata, int negnum, ccv_size_t size) -{ - FILE *w = fopen(file, "w"); - if (w == 0) - return -1; - fwrite(&negnum, sizeof(int), 1, w); - int i; - int isizs012 = _ccv_width_padding(size.width) * size.height + - _ccv_width_padding(size.width >> 1) * (size.height >> 1) + - _ccv_width_padding(size.width >> 2) * (size.height >> 2); - for (i = 0; i < negnum; i++) - fwrite(negdata[i], 1, isizs012, w); - fclose(w); - return 0; -} - -static int _ccv_resume_bbf_cascade_training_state(const char *file, int *i, int *k, int *bg, double *pw, double *nw, int posnum, int negnum) -{ - int stat = 0; - FILE *r = fopen(file, "r"); - if (r == 0) - return -1; - stat |= fscanf(r, "%d %d %d", i, k, bg); - int j; - union { - double db; - int i[2]; - } dbi; - for (j = 0; j < posnum; j++) - { - stat |= fscanf(r, "%d %d", &dbi.i[0], &dbi.i[1]); - pw[j] = dbi.db; - } - for (j = 0; j < negnum; j++) - { - stat |= fscanf(r, "%d %d", &dbi.i[0], &dbi.i[1]); - nw[j] = dbi.db; - } - fclose(r); - return 0; -} - -static int _ccv_save_bbf_cacade_training_state(const char *file, int i, int k, int bg, double *pw, double *nw, int posnum, int negnum) -{ - FILE *w = fopen(file, "w"); - if (w == 0) - return -1; - fprintf(w, "%d %d %d\n", i, k, bg); - int j; - union { - double db; - int i[2]; - } dbi; - for (j = 0; j < posnum; ++j) - { - dbi.db = pw[j]; - fprintf(w, "%d %d ", dbi.i[0], dbi.i[1]); - } - fprintf(w, "\n"); - for (j = 0; j < negnum; ++j) - { - dbi.db = nw[j]; - fprintf(w, "%d %d ", dbi.i[0], dbi.i[1]); - } - fprintf(w, "\n"); - fclose(w); - return 0; -} - -void ccv_bbf_classifier_cascade_new(ccv_dense_matrix_t **posimg, int posnum, char **bgfiles, int bgnum, int negnum, ccv_size_t size, const char *dir, ccv_bbf_new_param_t params) -{ - int i, j, k; - /* allocate memory for usage */ - ccv_bbf_classifier_cascade_t *cascade = (ccv_bbf_classifier_cascade_t *)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); - cascade->count = 0; - cascade->size = size; - cascade->stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(sizeof(ccv_bbf_stage_classifier_t)); - unsigned char **posdata = (unsigned char **)ccmalloc(posnum * sizeof(unsigned char *)); - unsigned char **negdata = (unsigned char **)ccmalloc(negnum * sizeof(unsigned char *)); - double *pw = (double *)ccmalloc(posnum * sizeof(double)); - double *nw = (double *)ccmalloc(negnum * sizeof(double)); - float *peval = (float *)ccmalloc(posnum * sizeof(float)); - float *neval = (float *)ccmalloc(negnum * sizeof(float)); - double inv_balance_k = 1. / params.balance_k; - /* balance factor k, and weighted with 0.01 */ - params.balance_k *= 0.01; - inv_balance_k *= 0.01; - - int steps[] = {_ccv_width_padding(cascade->size.width), - _ccv_width_padding(cascade->size.width >> 1), - _ccv_width_padding(cascade->size.width >> 2)}; - int isizs0 = steps[0] * cascade->size.height; - int isizs01 = isizs0 + steps[1] * (cascade->size.height >> 1); - - i = 0; - k = 0; - int bg = 0; - int cacheK = 10; - /* state resume code */ - char buf[1024]; - sprintf(buf, "%s/stat.txt", dir); - _ccv_resume_bbf_cascade_training_state(buf, &i, &k, &bg, pw, nw, posnum, negnum); - if (i > 0) - { - cascade->count = i; - ccfree(cascade->stage_classifier); - cascade->stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(i * sizeof(ccv_bbf_stage_classifier_t)); - for (j = 0; j < i; j++) - { - sprintf(buf, "%s/stage-%d.txt", dir, j); - _ccv_read_bbf_stage_classifier(buf, &cascade->stage_classifier[j]); - } - } - if (k > 0) - cacheK = k; - int rpos, rneg = 0; - if (bg) - { - sprintf(buf, "%s/negs.txt", dir); - _ccv_read_background_data(buf, negdata, &rneg, cascade->size); - } - - for (; i < params.layer; i++) - { - if (!bg) - { - rneg = _ccv_prepare_background_data(cascade, bgfiles, bgnum, negdata, negnum); - /* save state of background data */ - sprintf(buf, "%s/negs.txt", dir); - _ccv_write_background_data(buf, negdata, rneg, cascade->size); - bg = 1; - } - double totalw; - /* save state of cascade : level, weight etc. */ - sprintf(buf, "%s/stat.txt", dir); - _ccv_save_bbf_cacade_training_state(buf, i, k, bg, pw, nw, posnum, negnum); - ccv_bbf_stage_classifier_t classifier; - if (k > 0) - { - /* resume state of classifier */ - sprintf(buf, "%s/stage-%d.txt", dir, i); - _ccv_read_bbf_stage_classifier(buf, &classifier); - } - else - { - /* initialize classifier */ - for (j = 0; j < posnum; j++) - pw[j] = params.balance_k; - for (j = 0; j < rneg; j++) - nw[j] = inv_balance_k; - classifier.count = k; - classifier.threshold = 0; - classifier.feature = (ccv_bbf_feature_t *)ccmalloc(cacheK * sizeof(ccv_bbf_feature_t)); - classifier.alpha = (float *)ccmalloc(cacheK * 2 * sizeof(float)); - } - _ccv_prepare_positive_data(posimg, posdata, cascade->size, posnum); - rpos = _ccv_prune_positive_data(cascade, posdata, posnum, cascade->size); - PRINT(CCV_CLI_INFO, "%d postivie data and %d negative data in training\n", rpos, rneg); - /* reweight to 1.00 */ - totalw = 0; - for (j = 0; j < rpos; j++) - totalw += pw[j]; - for (j = 0; j < rneg; j++) - totalw += nw[j]; - for (j = 0; j < rpos; j++) - pw[j] = pw[j] / totalw; - for (j = 0; j < rneg; j++) - nw[j] = nw[j] / totalw; - for (;; k++) - { - /* get overall true-positive, false-positive rate and threshold */ - double tp = 0, fp = 0, etp = 0, efp = 0; - _ccv_bbf_eval_data(&classifier, posdata, rpos, negdata, rneg, cascade->size, peval, neval); - _ccv_sort_32f(peval, rpos, 0); - classifier.threshold = peval[(int)((1. - params.pos_crit) * rpos)] - 1e-6; - for (j = 0; j < rpos; j++) - { - if (peval[j] >= 0) - ++tp; - if (peval[j] >= classifier.threshold) - ++etp; - } - tp /= rpos; - etp /= rpos; - for (j = 0; j < rneg; j++) - { - if (neval[j] >= 0) - ++fp; - if (neval[j] >= classifier.threshold) - ++efp; - } - fp /= rneg; - efp /= rneg; - PRINT(CCV_CLI_INFO, "stage classifier real TP rate : %f, FP rate : %f\n", tp, fp); - PRINT(CCV_CLI_INFO, "stage classifier TP rate : %f, FP rate : %f at threshold : %f\n", etp, efp, classifier.threshold); - if (k > 0) - { - /* save classifier state */ - sprintf(buf, "%s/stage-%d.txt", dir, i); - _ccv_write_bbf_stage_classifier(buf, &classifier); - sprintf(buf, "%s/stat.txt", dir); - _ccv_save_bbf_cacade_training_state(buf, i, k, bg, pw, nw, posnum, negnum); - } - if (etp > params.pos_crit && efp < params.neg_crit) - break; - /* TODO: more post-process is needed in here */ - - /* select the best feature in current distribution through genetic algorithm optimization */ - ccv_bbf_feature_t best; - if (params.optimizer == CCV_BBF_GENETIC_OPT) - { - best = _ccv_bbf_genetic_optimize(posdata, rpos, negdata, rneg, params.feature_number, cascade->size, pw, nw); - } - else if (params.optimizer == CCV_BBF_FLOAT_OPT) - { - best = _ccv_bbf_convex_optimize(posdata, rpos, negdata, rneg, 0, cascade->size, pw, nw); - } - else - { - best = _ccv_bbf_genetic_optimize(posdata, rpos, negdata, rneg, params.feature_number, cascade->size, pw, nw); - best = _ccv_bbf_convex_optimize(posdata, rpos, negdata, rneg, &best, cascade->size, pw, nw); - } - double err = _ccv_bbf_error_rate(&best, posdata, rpos, negdata, rneg, cascade->size, pw, nw); - double rw = (1 - err) / err; - totalw = 0; - /* reweight */ - for (j = 0; j < rpos; j++) - { - unsigned char *u8[] = {posdata[j], posdata[j] + isizs0, posdata[j] + isizs01}; - if (!_ccv_run_bbf_feature(&best, steps, u8)) - pw[j] *= rw; - pw[j] *= params.balance_k; - totalw += pw[j]; - } - for (j = 0; j < rneg; j++) - { - unsigned char *u8[] = {negdata[j], negdata[j] + isizs0, negdata[j] + isizs01}; - if (_ccv_run_bbf_feature(&best, steps, u8)) - nw[j] *= rw; - nw[j] *= inv_balance_k; - totalw += nw[j]; - } - for (j = 0; j < rpos; j++) - pw[j] = pw[j] / totalw; - for (j = 0; j < rneg; j++) - nw[j] = nw[j] / totalw; - double c = log(rw); - PRINT(CCV_CLI_INFO, "coefficient of feature %d: %f\n", k + 1, c); - classifier.count = k + 1; - /* resizing classifier */ - if (k >= cacheK) - { - ccv_bbf_feature_t *feature = (ccv_bbf_feature_t *)ccmalloc(cacheK * 2 * sizeof(ccv_bbf_feature_t)); - memcpy(feature, classifier.feature, cacheK * sizeof(ccv_bbf_feature_t)); - ccfree(classifier.feature); - float *alpha = (float *)ccmalloc(cacheK * 4 * sizeof(float)); - memcpy(alpha, classifier.alpha, cacheK * 2 * sizeof(float)); - ccfree(classifier.alpha); - classifier.feature = feature; - classifier.alpha = alpha; - cacheK *= 2; - } - /* setup new feature */ - classifier.feature[k] = best; - classifier.alpha[k * 2] = -c; - classifier.alpha[k * 2 + 1] = c; - } - cascade->count = i + 1; - ccv_bbf_stage_classifier_t *stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(cascade->count * sizeof(ccv_bbf_stage_classifier_t)); - memcpy(stage_classifier, cascade->stage_classifier, i * sizeof(ccv_bbf_stage_classifier_t)); - ccfree(cascade->stage_classifier); - stage_classifier[i] = classifier; - cascade->stage_classifier = stage_classifier; - k = 0; - bg = 0; - for (j = 0; j < rpos; j++) - ccfree(posdata[j]); - for (j = 0; j < rneg; j++) - ccfree(negdata[j]); - } - - ccfree(neval); - ccfree(peval); - ccfree(nw); - ccfree(pw); - ccfree(negdata); - ccfree(posdata); - ccfree(cascade); -} -#else -void ccv_bbf_classifier_cascade_new(ccv_dense_matrix_t **posimg, int posnum, char **bgfiles, int bgnum, int negnum, ccv_size_t size, const char *dir, ccv_bbf_new_param_t params) -{ - fprintf(stderr, " ccv_bbf_classifier_cascade_new requires libgsl support, please compile ccv with libgsl.\n"); -} -#endif - -static int _ccv_is_equal(const void *_r1, const void *_r2, void *data) -{ - const ccv_comp_t *r1 = (const ccv_comp_t *)_r1; - const ccv_comp_t *r2 = (const ccv_comp_t *)_r2; - int distance = (int)(r1->rect.width * 0.25 + 0.5); - - return r2->rect.x <= r1->rect.x + distance && - r2->rect.x >= r1->rect.x - distance && - r2->rect.y <= r1->rect.y + distance && - r2->rect.y >= r1->rect.y - distance && - r2->rect.width <= (int)(r1->rect.width * 1.5 + 0.5) && - (int)(r2->rect.width * 1.5 + 0.5) >= r1->rect.width; -} - -static int _ccv_is_equal_same_class(const void *_r1, const void *_r2, void *data) -{ - const ccv_comp_t *r1 = (const ccv_comp_t *)_r1; - const ccv_comp_t *r2 = (const ccv_comp_t *)_r2; - int distance = (int)(r1->rect.width * 0.25 + 0.5); - - return r2->classification.id == r1->classification.id && - r2->rect.x <= r1->rect.x + distance && - r2->rect.x >= r1->rect.x - distance && - r2->rect.y <= r1->rect.y + distance && - r2->rect.y >= r1->rect.y - distance && - r2->rect.width <= (int)(r1->rect.width * 1.5 + 0.5) && - (int)(r2->rect.width * 1.5 + 0.5) >= r1->rect.width; -} - -ccv_array_t *ccv_bbf_detect_objects(ccv_dense_matrix_t *a, ccv_bbf_classifier_cascade_t **_cascade, int count, ccv_bbf_param_t params) -{ - int hr = a->rows / params.size.height; - int wr = a->cols / params.size.width; - double scale = pow(2., 1. / (params.interval + 1.)); - int next = params.interval + 1; - int scale_upto = (int)(log((double)ccv_min(hr, wr)) / log(scale)); - ccv_dense_matrix_t **pyr = (ccv_dense_matrix_t **)alloca((scale_upto + next * 2) * 4 * sizeof(ccv_dense_matrix_t *)); - memset(pyr, 0, (scale_upto + next * 2) * 4 * sizeof(ccv_dense_matrix_t *)); - if (params.size.height != _cascade[0]->size.height || params.size.width != _cascade[0]->size.width) - ccv_resample(a, &pyr[0], 0, a->rows * _cascade[0]->size.height / params.size.height, a->cols * _cascade[0]->size.width / params.size.width, CCV_INTER_AREA); - else - pyr[0] = a; - int i, j, k, t, x, y, q; - for (i = 1; i < ccv_min(params.interval + 1, scale_upto + next * 2); i++) - ccv_resample(pyr[0], &pyr[i * 4], 0, (int)(pyr[0]->rows / pow(scale, i)), (int)(pyr[0]->cols / pow(scale, i)), CCV_INTER_AREA); - for (i = next; i < scale_upto + next * 2; i++) - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4], 0, 0, 0); - if (params.accurate) - for (i = next * 2; i < scale_upto + next * 2; i++) - { - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 1], 0, 1, 0); - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 2], 0, 0, 1); - ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 3], 0, 1, 1); - } - ccv_array_t *idx_seq; - ccv_array_t *seq = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - ccv_array_t *seq2 = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - ccv_array_t *result_seq = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - /* detect in multi scale */ - for (t = 0; t < count; t++) - { - ccv_bbf_classifier_cascade_t *cascade = _cascade[t]; - float scale_x = (float)params.size.width / (float)cascade->size.width; - float scale_y = (float)params.size.height / (float)cascade->size.height; - ccv_array_clear(seq); - for (i = 0; i < scale_upto; i++) - { - int dx[] = {0, 1, 0, 1}; - int dy[] = {0, 0, 1, 1}; - int i_rows = pyr[i * 4 + next * 8]->rows - (cascade->size.height >> 2); - int steps[] = {pyr[i * 4]->step, pyr[i * 4 + next * 4]->step, pyr[i * 4 + next * 8]->step}; - int i_cols = pyr[i * 4 + next * 8]->cols - (cascade->size.width >> 2); - int paddings[] = {pyr[i * 4]->step * 4 - i_cols * 4, - pyr[i * 4 + next * 4]->step * 2 - i_cols * 2, - pyr[i * 4 + next * 8]->step - i_cols}; - for (q = 0; q < (params.accurate ? 4 : 1); q++) - { - unsigned char *u8[] = {pyr[i * 4]->data.u8 + dx[q] * 2 + dy[q] * pyr[i * 4]->step * 2, pyr[i * 4 + next * 4]->data.u8 + dx[q] + dy[q] * pyr[i * 4 + next * 4]->step, pyr[i * 4 + next * 8 + q]->data.u8}; - for (y = 0; y < i_rows; y++) - { - for (x = 0; x < i_cols; x++) - { - float sum; - int flag = 1; - ccv_bbf_stage_classifier_t *classifier = cascade->stage_classifier; - for (j = 0; j < cascade->count; ++j, ++classifier) - { - sum = 0; - float *alpha = classifier->alpha; - ccv_bbf_feature_t *feature = classifier->feature; - for (k = 0; k < classifier->count; ++k, alpha += 2, ++feature) - sum += alpha[_ccv_run_bbf_feature(feature, steps, u8)]; - if (sum < classifier->threshold) - { - flag = 0; - break; - } - } - if (flag) - { - ccv_comp_t comp; - comp.rect = ccv_rect((int)((x * 4 + dx[q] * 2) * scale_x + 0.5), (int)((y * 4 + dy[q] * 2) * scale_y + 0.5), (int)(cascade->size.width * scale_x + 0.5), (int)(cascade->size.height * scale_y + 0.5)); - comp.neighbors = 1; - comp.classification.id = t; - comp.classification.confidence = sum; - ccv_array_push(seq, &comp); - } - u8[0] += 4; - u8[1] += 2; - u8[2] += 1; - } - u8[0] += paddings[0]; - u8[1] += paddings[1]; - u8[2] += paddings[2]; - } - } - scale_x *= scale; - scale_y *= scale; - } - - /* the following code from OpenCV's haar feature implementation */ - if (params.min_neighbors == 0) - { - for (i = 0; i < seq->rnum; i++) - { - ccv_comp_t *comp = (ccv_comp_t *)ccv_array_get(seq, i); - ccv_array_push(result_seq, comp); - } - } - else - { - idx_seq = 0; - ccv_array_clear(seq2); - // group retrieved rectangles in order to filter out noise - int ncomp = ccv_array_group(seq, &idx_seq, _ccv_is_equal_same_class, 0); - ccv_comp_t *comps = (ccv_comp_t *)ccmalloc((ncomp + 1) * sizeof(ccv_comp_t)); - memset(comps, 0, (ncomp + 1) * sizeof(ccv_comp_t)); - - // count number of neighbors - for (i = 0; i < seq->rnum; i++) - { - ccv_comp_t r1 = *(ccv_comp_t *)ccv_array_get(seq, i); - int idx = *(int *)ccv_array_get(idx_seq, i); - - if (comps[idx].neighbors == 0) - comps[idx].classification.confidence = r1.classification.confidence; - - ++comps[idx].neighbors; - - comps[idx].rect.x += r1.rect.x; - comps[idx].rect.y += r1.rect.y; - comps[idx].rect.width += r1.rect.width; - comps[idx].rect.height += r1.rect.height; - comps[idx].classification.id = r1.classification.id; - comps[idx].classification.confidence = ccv_max(comps[idx].classification.confidence, r1.classification.confidence); - } - - // calculate average bounding box - for (i = 0; i < ncomp; i++) - { - int n = comps[i].neighbors; - if (n >= params.min_neighbors) - { - ccv_comp_t comp; - comp.rect.x = (comps[i].rect.x * 2 + n) / (2 * n); - comp.rect.y = (comps[i].rect.y * 2 + n) / (2 * n); - comp.rect.width = (comps[i].rect.width * 2 + n) / (2 * n); - comp.rect.height = (comps[i].rect.height * 2 + n) / (2 * n); - comp.neighbors = comps[i].neighbors; - comp.classification.id = comps[i].classification.id; - comp.classification.confidence = comps[i].classification.confidence; - ccv_array_push(seq2, &comp); - } - } - - // filter out small face rectangles inside large face rectangles - for (i = 0; i < seq2->rnum; i++) - { - ccv_comp_t r1 = *(ccv_comp_t *)ccv_array_get(seq2, i); - int flag = 1; - - for (j = 0; j < seq2->rnum; j++) - { - ccv_comp_t r2 = *(ccv_comp_t *)ccv_array_get(seq2, j); - int distance = (int)(r2.rect.width * 0.25 + 0.5); - - if (i != j && - r1.classification.id == r2.classification.id && - r1.rect.x >= r2.rect.x - distance && - r1.rect.y >= r2.rect.y - distance && - r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance && - r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance && - (r2.neighbors > ccv_max(3, r1.neighbors) || r1.neighbors < 3)) - { - flag = 0; - break; - } - } - - if (flag) - ccv_array_push(result_seq, &r1); - } - ccv_array_free(idx_seq); - ccfree(comps); - } - } - - ccv_array_free(seq); - ccv_array_free(seq2); - - ccv_array_t *result_seq2; - /* the following code from OpenCV's haar feature implementation */ - if (params.flags & CCV_BBF_NO_NESTED) - { - result_seq2 = ccv_array_new(sizeof(ccv_comp_t), 64, 0); - idx_seq = 0; - // group retrieved rectangles in order to filter out noise - int ncomp = ccv_array_group(result_seq, &idx_seq, _ccv_is_equal, 0); - ccv_comp_t *comps = (ccv_comp_t *)ccmalloc((ncomp + 1) * sizeof(ccv_comp_t)); - memset(comps, 0, (ncomp + 1) * sizeof(ccv_comp_t)); - - // count number of neighbors - for (i = 0; i < result_seq->rnum; i++) - { - ccv_comp_t r1 = *(ccv_comp_t *)ccv_array_get(result_seq, i); - int idx = *(int *)ccv_array_get(idx_seq, i); - - if (comps[idx].neighbors == 0 || comps[idx].classification.confidence < r1.classification.confidence) - { - comps[idx].classification.confidence = r1.classification.confidence; - comps[idx].neighbors = 1; - comps[idx].rect = r1.rect; - comps[idx].classification.id = r1.classification.id; - } - } - - // calculate average bounding box - for (i = 0; i < ncomp; i++) - if (comps[i].neighbors) - ccv_array_push(result_seq2, &comps[i]); - - ccv_array_free(result_seq); - ccfree(comps); - } - else - { - result_seq2 = result_seq; - } - - for (i = 1; i < scale_upto + next * 2; i++) - ccv_matrix_free(pyr[i * 4]); - if (params.accurate) - for (i = next * 2; i < scale_upto + next * 2; i++) - { - ccv_matrix_free(pyr[i * 4 + 1]); - ccv_matrix_free(pyr[i * 4 + 2]); - ccv_matrix_free(pyr[i * 4 + 3]); - } - if (params.size.height != _cascade[0]->size.height || params.size.width != _cascade[0]->size.width) - ccv_matrix_free(pyr[0]); - - return result_seq2; -} - -ccv_bbf_classifier_cascade_t *ccv_bbf_read_classifier_cascade(const char *directory) -{ - char buf[1024]; - sprintf(buf, "%s/cascade.txt", directory); - int s, i; - FILE *r = fopen(buf, "r"); - if (r == 0) - return 0; - ccv_bbf_classifier_cascade_t *cascade = (ccv_bbf_classifier_cascade_t *)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); - s = fscanf(r, "%d %d %d", &cascade->count, &cascade->size.width, &cascade->size.height); - assert(s > 0); - cascade->stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(cascade->count * sizeof(ccv_bbf_stage_classifier_t)); - for (i = 0; i < cascade->count; i++) - { - sprintf(buf, "%s/stage-%d.txt", directory, i); - if (_ccv_read_bbf_stage_classifier(buf, &cascade->stage_classifier[i]) < 0) - { - cascade->count = i; - break; - } - } - fclose(r); - return cascade; -} - -ccv_bbf_classifier_cascade_t *ccv_bbf_classifier_cascade_read_binary(char *s) -{ - int i; - ccv_bbf_classifier_cascade_t *cascade = (ccv_bbf_classifier_cascade_t *)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); - memcpy(&cascade->count, s, sizeof(cascade->count)); - s += sizeof(cascade->count); - memcpy(&cascade->size.width, s, sizeof(cascade->size.width)); - s += sizeof(cascade->size.width); - memcpy(&cascade->size.height, s, sizeof(cascade->size.height)); - s += sizeof(cascade->size.height); - ccv_bbf_stage_classifier_t *classifier = cascade->stage_classifier = (ccv_bbf_stage_classifier_t *)ccmalloc(cascade->count * sizeof(ccv_bbf_stage_classifier_t)); - for (i = 0; i < cascade->count; i++, classifier++) - { - memcpy(&classifier->count, s, sizeof(classifier->count)); - s += sizeof(classifier->count); - memcpy(&classifier->threshold, s, sizeof(classifier->threshold)); - s += sizeof(classifier->threshold); - classifier->feature = (ccv_bbf_feature_t *)ccmalloc(classifier->count * sizeof(ccv_bbf_feature_t)); - classifier->alpha = (float *)ccmalloc(classifier->count * 2 * sizeof(float)); - memcpy(classifier->feature, s, classifier->count * sizeof(ccv_bbf_feature_t)); - s += classifier->count * sizeof(ccv_bbf_feature_t); - memcpy(classifier->alpha, s, classifier->count * 2 * sizeof(float)); - s += classifier->count * 2 * sizeof(float); - } - return cascade; -} - -int ccv_bbf_classifier_cascade_write_binary(ccv_bbf_classifier_cascade_t *cascade, char *s, int slen) -{ - int i; - int len = sizeof(cascade->count) + sizeof(cascade->size.width) + sizeof(cascade->size.height); - ccv_bbf_stage_classifier_t *classifier = cascade->stage_classifier; - for (i = 0; i < cascade->count; i++, classifier++) - len += sizeof(classifier->count) + sizeof(classifier->threshold) + classifier->count * sizeof(ccv_bbf_feature_t) + classifier->count * 2 * sizeof(float); - if (slen >= len) - { - memcpy(s, &cascade->count, sizeof(cascade->count)); - s += sizeof(cascade->count); - memcpy(s, &cascade->size.width, sizeof(cascade->size.width)); - s += sizeof(cascade->size.width); - memcpy(s, &cascade->size.height, sizeof(cascade->size.height)); - s += sizeof(cascade->size.height); - classifier = cascade->stage_classifier; - for (i = 0; i < cascade->count; i++, classifier++) - { - memcpy(s, &classifier->count, sizeof(classifier->count)); - s += sizeof(classifier->count); - memcpy(s, &classifier->threshold, sizeof(classifier->threshold)); - s += sizeof(classifier->threshold); - memcpy(s, classifier->feature, classifier->count * sizeof(ccv_bbf_feature_t)); - s += classifier->count * sizeof(ccv_bbf_feature_t); - memcpy(s, classifier->alpha, classifier->count * 2 * sizeof(float)); - s += classifier->count * 2 * sizeof(float); - } - } - return len; -} - -void ccv_bbf_classifier_cascade_free(ccv_bbf_classifier_cascade_t *cascade) -{ - int i; - for (i = 0; i < cascade->count; ++i) - { - ccfree(cascade->stage_classifier[i].feature); - ccfree(cascade->stage_classifier[i].alpha); - } - ccfree(cascade->stage_classifier); - ccfree(cascade); -} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 7c6e2b7..26f66ad 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "lib": [ - "es2015" + "es6" ], "module": "commonjs", "allowUnreachableCode": false, diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..5cd744e --- /dev/null +++ b/tslint.json @@ -0,0 +1,7 @@ +{ + "extends": "tslint-xo", + "rules": { + "comment-format": false, + "indent": [true, "spaces"] + } +} diff --git a/yarn.lock b/yarn.lock index 615aef3..5078c18 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,22 @@ # yarn lockfile v1 +"@fimbul/bifrost@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@fimbul/bifrost/-/bifrost-0.6.0.tgz#5150302b63e1bd37ff95f561c3605949cb7e3770" + dependencies: + "@fimbul/ymir" "^0.6.0" + get-caller-file "^1.0.2" + tslib "^1.8.1" + +"@fimbul/ymir@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@fimbul/ymir/-/ymir-0.6.0.tgz#537cb15d361b7c993fe953b48c898ecdf4f671b8" + dependencies: + inversify "^4.10.0" + reflect-metadata "^0.1.12" + tslib "^1.8.1" + "@types/chalk@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba" @@ -127,29 +143,11 @@ abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - dependencies: - acorn "^3.0.4" - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -acorn@^5.5.0: - version "5.5.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" - add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" -ajv-keywords@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" - -ajv@^5.1.0, ajv@^5.3.0: +ajv@^5.1.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: @@ -158,15 +156,6 @@ ajv@^5.1.0, ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^6.0.1: - version "6.4.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.4.0.tgz#d3aff78e9277549771daf0164cff48482b754fc6" - dependencies: - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - uri-js "^3.0.2" - align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -195,10 +184,6 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" -ansi-escapes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - ansi-gray@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" @@ -912,7 +897,7 @@ buffer-from@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" -builtin-modules@^1.0.0: +builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -937,16 +922,6 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -989,7 +964,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@*, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.2.0: +chalk@*, chalk@^2.2.0: version "2.4.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52" dependencies: @@ -1017,6 +992,14 @@ chalk@^0.5.1: strip-ansi "^0.3.0" supports-color "^0.2.0" +chalk@^2.3.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" @@ -1040,10 +1023,6 @@ chownr@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -1168,7 +1147,7 @@ commander@2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" -commander@^2.9.0: +commander@^2.12.1, commander@^2.9.0: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" @@ -1187,7 +1166,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.10, concat-stream@^1.5.0, concat-stream@^1.6.0: +concat-stream@^1.4.10, concat-stream@^1.5.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: @@ -1372,7 +1351,7 @@ cpx@1.5.0: shell-quote "^1.6.1" subarg "^1.0.0" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -1466,7 +1445,7 @@ dateformat@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" -debug@3.1.0, debug@^3.1.0: +debug@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -1503,10 +1482,6 @@ deep-extend@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - defaults@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" @@ -1539,18 +1514,6 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -del@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -1581,11 +1544,16 @@ diff@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" +diff@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + +doctrine@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" dependencies: - esutils "^2.0.2" + esutils "^1.1.6" + isarray "0.0.1" dom-serializer@0: version "0.1.0" @@ -1697,89 +1665,13 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0, escape-string-regexp@^1 version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -eslint-plugin-standard@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" - -eslint-scope@^3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-visitor-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" - -eslint@4.17.0: - version "4.17.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.17.0.tgz#dc24bb51ede48df629be7031c71d9dc0ee4f3ddf" - dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" - chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" - debug "^3.1.0" - doctrine "^2.1.0" - eslint-scope "^3.7.1" - eslint-visitor-keys "^1.0.0" - espree "^3.5.2" - esquery "^1.0.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" - imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" - progress "^2.0.0" - require-uncached "^1.0.3" - semver "^5.3.0" - strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "^4.0.1" - text-table "~0.2.0" - -espree@^3.5.2: - version "3.5.4" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" - dependencies: - acorn "^5.5.0" - acorn-jsx "^3.0.0" - esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" -esquery@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - dependencies: - estraverse "^4.0.0" - -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - dependencies: - estraverse "^4.1.0" - -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" +esutils@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.1.6.tgz#c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375" esutils@^2.0.2: version "2.0.2" @@ -1862,7 +1754,7 @@ extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" -external-editor@^2.0.1, external-editor@^2.0.4: +external-editor@^2.0.1: version "2.2.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: @@ -1913,10 +1805,6 @@ fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - fd-slicer@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" @@ -1936,13 +1824,6 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -2010,15 +1891,6 @@ flagged-respawn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.0.tgz#4e79ae9b2eb38bf86b3bb56bf3e0a56aa5fcabd7" -flat-cache@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" - dependencies: - circular-json "^0.3.1" - del "^2.0.2" - graceful-fs "^4.1.2" - write "^0.2.1" - for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -2109,10 +1981,6 @@ function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -2142,7 +2010,7 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" -get-caller-file@^1.0.1: +get-caller-file@^1.0.1, get-caller-file@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -2260,7 +2128,7 @@ glob2base@^0.0.12: dependencies: find-index "^0.1.1" -glob@7.1.2, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: +glob@7.1.2, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -2316,25 +2184,10 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -globals@^11.0.1: - version "11.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.4.0.tgz#b85c793349561c16076a3c13549238a27945f1bc" - globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" -globby@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - globule@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5" @@ -2704,14 +2557,6 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^3.3.3: - version "3.3.7" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - indent-string@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" @@ -2759,25 +2604,6 @@ inquirer@3.0.6: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - interpret@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" @@ -2788,6 +2614,10 @@ invariant@^2.2.2: dependencies: loose-envify "^1.0.0" +inversify@^4.10.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/inversify/-/inversify-4.13.0.tgz#0ab40570bfa4474b04d5b919bbab3a4f682a72f5" + invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -2963,22 +2793,6 @@ is-odd@^2.0.0: dependencies: is-number "^4.0.0" -is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - -is-path-in-cwd@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" - dependencies: - is-path-inside "^1.0.0" - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - dependencies: - path-is-inside "^1.0.1" - is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -3017,10 +2831,6 @@ is-relative@^1.0.0: dependencies: is-unc-path "^1.0.0" -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -3095,7 +2905,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@^3.9.1: +js-yaml@^3.7.0: version "3.11.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" dependencies: @@ -3137,10 +2947,6 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - json-stable-stringify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" @@ -3216,13 +3022,6 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - liftoff@^2.1.0: version "2.5.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec" @@ -3665,10 +3464,6 @@ natives@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.3.tgz#44a579be64507ea2d6ed1ca04a9415915cf75558" -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - needle@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.0.tgz#f14efc69cee1024b72c8b21c7bdf94a731dc12fa" @@ -3885,17 +3680,6 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - orchestrator@^0.3.0: version "0.3.8" resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e" @@ -4018,10 +3802,6 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1, path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - path-key@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -4118,18 +3898,10 @@ plugin-log@^0.1.0: chalk "^1.1.1" dateformat "^1.0.11" -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" @@ -4146,10 +3918,6 @@ process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" -progress@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" - pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -4158,10 +3926,6 @@ punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" -punycode@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - q@^1.1.2, q@^1.4.1, q@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -4314,6 +4078,10 @@ redent@^2.0.0: indent-string "^3.0.0" strip-indent "^2.0.0" +reflect-metadata@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" + regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" @@ -4451,13 +4219,6 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -4469,15 +4230,11 @@ resolve-dir@^1.0.0, resolve-dir@^1.0.1: expand-tilde "^2.0.0" global-modules "^1.0.0" -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" -resolve@^1.1.6, resolve@^1.1.7: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: version "1.7.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" dependencies: @@ -4500,7 +4257,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@2.6.2, rimraf@^2.2.8, rimraf@^2.6.1: +rimraf@2, rimraf@2.6.2, rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -4520,16 +4277,6 @@ run-sequence@2.2.1: fancy-log "^1.3.2" plugin-error "^0.1.2" -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - rx@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" @@ -4621,12 +4368,6 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - dependencies: - is-fullwidth-code-point "^2.0.0" - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -4834,7 +4575,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +string-width@^2.0.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -4960,17 +4701,6 @@ svgo@1.0.4: unquote "~1.1.1" util.promisify "~1.0.0" -table@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" - dependencies: - ajv "^6.0.1" - ajv-keywords "^3.0.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" - tar@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" @@ -5004,7 +4734,7 @@ text-extensions@^1.0.0: version "1.7.0" resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.7.0.tgz#faaaba2625ed746d568a23e4d0aacd9bf08a8b39" -text-table@^0.2.0, text-table@~0.2.0: +text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -5103,6 +4833,69 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" +tslib@1.9.0, tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1: + version "1.9.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" + +tslint-consistent-codestyle@^1.11.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/tslint-consistent-codestyle/-/tslint-consistent-codestyle-1.13.0.tgz#82abf230bf39e01159b4e9af721d489dd5ae0e6c" + dependencies: + "@fimbul/bifrost" "^0.6.0" + tslib "^1.7.1" + tsutils "^2.24.0" + +tslint-eslint-rules@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-5.1.0.tgz#3232b318da55dbb5a83e3f5d657c1ddbb27b9ff2" + dependencies: + doctrine "0.7.2" + tslib "1.9.0" + tsutils "2.8.0" + +tslint-microsoft-contrib@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/tslint-microsoft-contrib/-/tslint-microsoft-contrib-5.0.3.tgz#6fc3e238179cd72045c2b422e4d655f4183a8d5c" + dependencies: + tsutils "^2.12.1" + +tslint-xo@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/tslint-xo/-/tslint-xo-0.7.2.tgz#7523e9f2819e23c5ce66b501e4b76067c1e6f637" + dependencies: + tslint-consistent-codestyle "^1.11.0" + tslint-eslint-rules "^5.1.0" + tslint-microsoft-contrib "^5.0.2" + +tslint@5.9.1: + version "5.9.1" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae" + dependencies: + babel-code-frame "^6.22.0" + builtin-modules "^1.1.1" + chalk "^2.3.0" + commander "^2.12.1" + diff "^3.2.0" + glob "^7.1.1" + js-yaml "^3.7.0" + minimatch "^3.0.4" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.8.0" + tsutils "^2.12.1" + +tsutils@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.8.0.tgz#0160173729b3bf138628dd14a1537e00851d814a" + dependencies: + tslib "^1.7.1" + +tsutils@^2.12.1, tsutils@^2.24.0: + version "2.26.2" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.26.2.tgz#a9f9f63434a456a5e0c95a45d9a59181cb32d3bf" + dependencies: + tslib "^1.8.1" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -5117,19 +4910,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - dependencies: - prelude-ls "~1.1.2" - typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.1.tgz#bb3682c2c791ac90e7c6210b26478a8da085c359" +typescript@2.8.3: + version "2.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.3.tgz#5d817f9b6f31bb871835f4edf0089f21abe6c170" uglify-js@^2.6: version "2.8.29" @@ -5179,12 +4966,6 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" -uri-js@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-3.0.2.tgz#f90b858507f81dea4dcfbb3c4c3dbfa2b557faaa" - dependencies: - punycode "^2.1.0" - urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -5381,10 +5162,6 @@ wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -5396,12 +5173,6 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - dependencies: - mkdirp "^0.5.1" - "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"